Reputation: 765
Let's say I have a struct with a slice parameter like the following, and I create one and fill it with some values:
type s struct {
sl []float32
}
func NewS() *s {
return &s{
sl: make([]float32, 3),
}
}
func main() {
a := NewS()
a.sl[0] = 1
a.sl[1] = 2
a.sl[2] = 3
b := NewS()
// Code here
}
I want b
to have an sl
with the same values as a.sl
, and in particular, I'd like to understand how to do it in different ways:
b
points to the entire a
(so that if there were other parameters in the struct, those would all match)b.sl
would point to a.sl
What follows is what I've tried and found so far.
b = a
fmt.Printf("a: %p\n", &a)
fmt.Printf("b: %p\n", &b)
fmt.Printf("a.sl: %p\n", &a.sl)
fmt.Printf("b.sl: %p\n", &b.sl)
Which outputs different memory addresses for the structs, but the same memory addresses for the slices. Why is that? Why wouldn't the struct addresses be the same, too, if a is just pointing to b?
a: 0xc00000e030
b: 0xc00000e038
a.sl: 0xc000054040
b.sl: 0xc000054040
Then I tried:
b.sl = a.sl
// ...
Which outputs all distinct memory addresses. It makes sense of course that the address of a
and b
are different, but why isn't b.sl
pointing to the address of a.sl
?
a: 0xc00000e028
b: 0xc00000e030
a.sl: 0xc00000c030
b.sl: 0xc00000c048
And finally I tried:
copy(b.sl, a.sl)
// ...
Which outputs similarly to the above. This result is the only one I expected, since I expected this to make a deep copy.
a: 0xc0000b8018
b: 0xc0000b8020
a.sl: 0xc0000ae018
b.sl: 0xc0000ae030
Could you help me understand what's happening in these 3 cases and other ways to achieve my desire results and perform various types of copies?
Upvotes: 1
Views: 1741
Reputation:
Here's some background information: A slice contains a pointer to the slice's backing array, the length of the slice and the capacity of the backing array. The (pointer, length, capacity) is referred to as a slice header.
The address of a slice is the address of the slice header, not the pointer to the slice's backing array or the first element of the slice's backing array.
b = a
The variables a
and b
point to the same value after the statement is executed.
The variables a and b are distinct and therefore have different addresses.
The expression &a.sl
is the address of the sl
field in the pointed at value. The expression &b.sl
equals &a.sl
because a
and b
point at the same value.
This is your #1: a
an b
point at the same value.
b.sl = a.sl
The statement copies the slice header from a.sl
to b.sl
. The slices have different addresses because slice headers remain distinct.
This is close to your #2: a.sl
an b.sl
point at the same backing array. A modification to an element in a.sl
is visible through b.sl
, but changes to the slice header a.sl
are not reflected in `b.sl.
copy(b.sl, a.sl)
The statement copies the elements in a.sl
s backing array to b.sl
.
This is your #3, a deep copy. Changes through a
are not reflected in b
.
Upvotes: 2
Reputation: 51587
A slice is a triple containing a pointer to the underlying array, length, and capacity. When you assign a slice to another slice, you assign that triple. The underlying array remains the same.
A slice is a view of an array. If you need a deep copy of a slice, you have to create another slice and copy it yourself.
If you assign an array to another, that copies each element of the source to the target.
Upvotes: 1