0

I am passing a struct to a function by reference.

I was expecting if I define and change the struct inside the function I can get the new value outside.

But it is not happening.

Can anyone explain why?

package main

import "fmt"

func intbyRef(i *int) {
    *i = 10
}

type ttt struct {
    a int
}

func change(t *ttt) {
    var p ttt = ttt{7}
    fmt.Println(p)
    t = &p

}

func main() {

    i := 1
    var t *ttt

    fmt.Println(i)
    fmt.Println(t)

    change(t)
    intbyRef(&i)

    fmt.Println(i)
    fmt.Println(t)
}

You can try the code in here: https://play.golang.org/p/I-GIdIZ9c6

Ikomi Kara
  • 11
  • 1
  • 1
  • 1
    Please consider unlearning this "by reference" misnomer. In some languages, there *is* the distinction: say, in Python and PHP, values of integer type are passed by value and objects of class types are passed by reference. In contrast, in Go, all values are passed by value, just you can *explicitly* pass pointers to values -- if you want the callee to modify the value pointed to, or want to avoid copying overhead. – kostix Dec 28 '15 at 16:48
  • 1
    Consider reading [this](http://stackoverflow.com/a/25354231/720999) and [this](http://stackoverflow.com/a/23551970/720999). – kostix Dec 28 '15 at 16:53

3 Answers3

2

You are not changing the struct inside the function, you are changing the value by setting it to a different memory address. In other words, you're not changing the object stored at the address referenced by t, you're changing the pointer value of t itself, which will not change the pointer value of the t variable outside the function (because Golang is pass by value).

In order to do what you want, the code should look similar to what you're doing for intbyRef, namely:

func change(t *ttt) {
    var p ttt = ttt{7}
    fmt.Println(p)
    *t = p
}

however, this will panic with a nil-pointer dereference. Your main function should also do what you're doing with the int:

func main() {

    i := 1
    // var t *ttt
    t := new(ttt)

    ...
}

Full code below (playground link here):

package main

import "fmt"

func intbyRef(i *int) {
    *i = 10
}

type ttt struct {
    a int
}

func change(t *ttt) {
    var p ttt = ttt{7}
    fmt.Println(p)
    // t = &p
    *t = p

}

func main() {

    i := 1
    // var t *ttt
    t := new(ttt)

    fmt.Println(i)
    fmt.Println(t)

    change(t)
    intbyRef(&i)

    fmt.Println(i)
    fmt.Println(t)
}

Also, you may want to be guarding against nil values and returning errors, especially for functions internal to your package.

Amit Kumar Gupta
  • 17,184
  • 7
  • 46
  • 64
  • 1
    Regarding «in general, you should be guarding against nil values and returning errors.» -- please don't! [Here's](http://stackoverflow.com/a/22865084/720999) why. – kostix Dec 28 '15 at 16:44
0

In our code, you are creating new object of ttt in function change and assigning it to t which is passed as parameter to function. In go parameters are passed by value, so when at the end of function change you assign value to t is only for the scope of the function. In order to propagate change to calling function return value from change and assign it back.

Have made the changes to your code, please check play ground link https://play.golang.org/p/S3GK0JLDHn

Prashant Thakkar
  • 1,383
  • 1
  • 12
  • 15
0

You are passing initialized pointer value to intByRef and change the dereferenced value.

In the change you are passing not initialized pointer value (aka nil) and assigning another pointer to it.

So you are doing two different things.

You should know that when you pass a pointer to a function you pass a copy of that pointer (pointing to the same value). That's why main's t is unchanged after passing it to change. It points to the "old" memory address.

If you want to change a value of ttt pointer passed to the function you can do it like you do it in intByRef, but the pointer must be initialized (aka. allocated). Otherwise you'd try to dereference nil.

playground

func change(t *ttt) {
    var p ttt = ttt{7}
    fmt.Println(p)
    *t = p
}

func main() {
    t := new(ttt)
    fmt.Println(t)
    change(t)
    fmt.Println(t)
}
kopiczko
  • 3,018
  • 1
  • 17
  • 24