The user with no hat
The user with no hat

Reputation: 10846

Why a slice []struct doesn't behave same as []builtin?

The slices are references to the underlying array. This makes sense and seems to work on builtin/primitive types but why is not working on structs? I assume that even if I update a struct field the reference/address is still the same.

package main

import "fmt"

type My struct {
    Name string
}

func main() {
    x := []int{1}
    update2(x)
    fmt.Println(x[0])
    update(x)
    fmt.Println(x[0])
    my := My{Name: ""}
    update3([]My{my})
    // Why my[0].Name is not "many" ?
    fmt.Println(my)
}

func update(x []int) {
    x[0] = 999
    return
}
func update2(x []int) {
    x[0] = 1000
    return
}
func update3(x []My) {
    x[0].Name = "many"
    return
}

To clarify: I'm aware that I could use pointers for both cases. I'm only intrigued why the struct is not updated (unlike the int).

Upvotes: 1

Views: 99

Answers (3)

Doug Henderson
Doug Henderson

Reputation: 888

Your third test is not the same as the first two. Look at this (Playground). In this case, you do not need to use pointers as you are not modifying the slice itself. You are modifying an element of the underlying array. If you wanted to modify the slice, by for instance, appending a new element, you would need to use a pointer to pass the slice by reference. Notice that I changed the prints to display the type as well as the value.

Upvotes: 0

Denys Séguret
Denys Séguret

Reputation: 382112

What you do when calling update3 is you pass a new array, containing copies of the value, and you immediately discard the array. This is different from what you do with the primitive, as you keep the array.

There are two approaches here.

1) use an array of pointers instead of an array of values:

You could define update3 like this:

func update3(x []*My) {
    x[0].Name = "many"
    return
}

and call it using

update3([]*My{&my})

2) write in the array (in the same way you deal with the primitive)

arr := make([]My,1)
arr[0] = My{Name: ""}
update3(arr)

Upvotes: 2

IamNaN
IamNaN

Reputation: 6864

From the GO FAQ:

As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter. For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to. (See the next section for a discussion of how this affects method receivers.)

Map and slice values behave like pointers: they are descriptors that contain pointers to the underlying map or slice data. Copying a map or slice value doesn't copy the data it points to.

Thus when you pass my you are passing a copy of your struct and the calling code won't see any changes made to that copy.

To have the function change the data in teh struct you have to pass a pointer to the struct.

Upvotes: 0

Related Questions