6 ms·
No, there is no "hiding" of a "reference". There is copying a struct: s2 := s1 This copies the struct in `s1` into a new name `s2`. This struct contains,
by usrbinbash 2y ago
No, there is no "hiding" of a "reference". There is copying a struct:
s2 := s1
This copies the struct in `s1` into a new name `s2`. This struct contains, among other things, a pointer to the backing array. Therefore, when you assign to the slice
s2[0] = "bye"
You assign to the same backing array. Slices are not arrays. Copying a slice copies a struct containing a pointer to an array. A similar situation holds true for maps. The same logic that is universal throughout the language, aka. "Go only ever copies things by value" holds true for all of these types.
https://go.dev/ref/spec#Slice_types https://go.dev/ref/spec#Slice_types
"A slice, once initialized, is always associated with an underlying array that holds its elements. A slice therefore shares storage with its array and with other slices of the same array; by contrast, distinct arrays always represent distinct storage."
- Joker_vD 2y agoSince a slice/map, internally, contains a pointer to the data, it looks like slices/maps have reference semantics: after you do "m2 := m1", all changes done through m1 are visible through m2, even though the type of m1 and m2 has no visible asterisk anywhere in it.
- usrbinbash 2y ago> , it looks like slices/maps have reference semantics No, they don't. Pointers and references are fundamentally different concepts. A reference is a name, handled by the runtime, that is bound to an entity. A pointer is just a value of type `uintptr`. When I "copy" a reference, I simply instruct the runtime to bind another name to the entity. When I copy a struct containing a pointer, I actually allocate new memory to contain a new copy of that `uintptr`. And since that copy is a true copy of a pointer-value, I can change it. That's why this: func main() { s1 := []int{1, 2} s2 := s1 s2 = append(s2, 3) s1[0] = 42 fmt.Println(s1) fmt.Println(s2) } Will give you [42 2] [1 2 3] as an output. s2 is not a "Reference" to the same entity as s1, it is a struct holding a pointer, and when we grow the slice this struct represents beyond the capacity of the backing array that pointer points to, by appending to it, we replace that pointer in s2. Comparing that to a language that actually does have reference semantics (python): s1 = [1, 2] s2 = s1 s2.append(3) s1[0] = 42 print(s1) print(s2) Gives me [42, 2, 3] [42, 2, 3]