In Go if I have a custom type inherited from let's say a slice of integers if I cast an array of integers to my custom type would it involve new memory allocation?
http://play.golang.org/p/cNpKELZ3X- :
package main
import (
"fmt"
)
type MyIntsArray []int
func (a MyIntsArray) Sum() int {
sum := 0
for _, i := range a {
sum += i
}
return sum
}
func main() {
myInts := []int{1,2,3,5,7,11}
myIntsArr := MyIntsArray(myInts)
fmt.Println(fmt.Sprintf("myInts: %v, myIntsArr: %v, Sum: %v", myInts, myIntsArr, myIntsArr.Sum()))
}
Update: OK, for slices there is no memory allocation as slices are pointers.
But I have more general question. How about structs? Seems it makes copy: http://play.golang.org/p/NXgM8Cr-qj and it is because of working with value types.
I am trying to figure out if I can cast a pointer to a struct to a pointer of a different type. Something like this: http://play.golang.org/p/BV086ZAeGf
package main
import (
"fmt"
)
type MyType1 struct {
Val int
Values []int
}
type MyType2 MyType1
func main() {
t1 := &MyType1{Val: -1, Values: []int{1,3,5}}
var t2 *MyType2
t2 = *MyType2(t1)
fmt.Printf("t1: %v, t2: %v
", t1, t2)
t1.Val = -10
t1.Values[1] = 200
fmt.Printf("t1: %v, t2: %v
", t1, t2)
}
prog.go:17: cannot convert t1 (type *MyType1) to type MyType2
prog.go:17: invalid indirect of MyType2(t1) (type MyType2)
No. You will work on the same memory. Slices are pointers, so the default "copying" of a slice means copying the address itself, not the value found at that address.
http://play.golang.org/p/vy-c7sS9Fz
package main
import (
"fmt"
)
type MyIntsArray []int
func (a MyIntsArray) Sum() int {
sum := 0
for _, i := range a {
sum += i
}
return sum
}
func main() {
myInts := []int{1,2,3,5,7,11}
myIntsArr := MyIntsArray(myInts)
fmt.Printf("myInts: %v, %p, myIntsArr: %v, %p, Sum: %v
", myInts, myInts, myIntsArr, myIntsArr, myIntsArr.Sum())
for i, _ := range myInts {
fmt.Printf("myInt: %v, %p, myIntsArr elem: %v, %p
", myInts[i], &myInts[i], myIntsArr[i], &myIntsArr[i])
}
myInts[0] = 100
fmt.Printf("myInts: %v, %p, myIntsArr: %v, %p, Sum: %v
", myInts, myInts, myIntsArr, myIntsArr, myIntsArr.Sum())
myIntsArr[1] = 200
fmt.Printf("myInts: %v, %p, myIntsArr: %v, %p, Sum: %v
", myInts, myInts, myIntsArr, myIntsArr, myIntsArr.Sum())
}
As you can see, all the addresses are identical for each element, and when you change one value from one variable item, the same value is available on the other.
Go doesn't support casting between pointers to different structs. If you really want to you can use unsafe
package which contains special type unsafe.Pointer
which supports operations that no other type does:
- A pointer value of any type can be converted to a Pointer.
- A Pointer can be converted to a pointer value of any type.
- A uintptr can be converted to a Pointer.
- A Pointer can be converted to a uintptr.
http://play.golang.org/p/fhOptEOQ74
package main
import (
"fmt"
"unsafe"
)
type MyType1 struct {
Val int
Values []int32
}
type MyType2 struct {
Val int
Values []float32
}
func main() {
t1 := &MyType1{Val: -1, Values: []int32{1,3,5}}
p := unsafe.Pointer(t1)
var t2 *MyType2 = (*MyType2)(p)
fmt.Printf("t1: %v, t2: %v
", t1, t2)
t1.Val = -10
t1.Values[1] = 200
fmt.Printf("t1: %v, t2: %v
", t1, t2)
t2.Val = -20
t2.Values[1] = 1.2345
fmt.Printf("t1: %v, t2: %v
", t1, t2)
}
The code will print:
t1: &{-1 [1 3 5]}, t2: &{-1 [1e-45 4e-45 7e-45]}
t1: &{-10 [1 200 5]}, t2: &{-10 [1e-45 2.8e-43 7e-45]}
t1: &{-20 [1 1067320345 5]}, t2: &{-20 [1e-45 1.2345 7e-45]}