Search code examples
functionpointersgoreferencereturn

Function is not changing the pointer after return


Language is 'Go' ('Golang').

The Function initApp is receiving a Pointer to an Object ('struct' in Go). Inside the Function I create a new Object Pointer and initialize the Value of the Object. Printing and Debugger both show that before the Function's Return everything is good. But after the Return, the Pointer which was the Function's Argument has the same empty Value as before the Function Call.

Why is that so?

Code is here: https://pastebin.com/0Gww2CQC

// ptr.go.

package main

import "fmt"

type ClassX struct {
    Name string
    Age  int
}

func main() {
    var obj *ClassX
    initApp(obj)
    fmt.Println(obj)
    return
}

func initApp(x *ClassX) {
    tmp := NewClassXObject()
    x = tmp
    fmt.Println("tmp:", tmp)
    fmt.Println("x:", x)
}

func NewClassXObject() *ClassX {
    x := new(ClassX)
    x.init()
    return x
}

func (o *ClassX) init() {
    o.Age = 123
    o.Name = "John"
}

The Output is following:

tmp: &{John 123} x: &{John 123} <nil>

Thank You!


Solution

  • Remember, everything in Go is passed by value. When you pass a pointer, you're passing the pointer by value. Your function argument is a new local variable with the same value as was passed to it by the caller; i.e. a new pointer which points to the same memory location. So your code:

    func initApp(x *ClassX) {
        tmp := NewClassXObject()
        x = tmp
        fmt.Println("tmp:", tmp)
        fmt.Println("x:", x)
    }
    

    Creates a new *ClassX in tmp, then overwrites x with the new pointer to a new memory location, then returns. None of that has any impact on the caller's scope; the pointer the caller passed still points to the same memory address it did before. You can change the value that x points to:

    func initApp(x *ClassX) {
        tmp := NewClassXObject()
        *x = *tmp
        fmt.Println("tmp:", tmp)
        fmt.Println("x:", x)
    }
    

    Now you have two pointers to two separate memory locations, and you're copying the value that one points to into the memory the other points to, so that they both point at two identical values in two separate memory locations. This is what you would do if you wanted to overwrite the value pointed to by the caller.

    However, since this creates a new value, it seems likely that what you want is not to overwrite the caller's value, but to return a new value. The uses of pointers as "output parameters" are very, very limited in Go; because you can return multiple values, you almost always just want to return the value rather than updating a pointer argument:

    func initApp() *ClassX {
        return NewClassXObject()
    }
    
    func main() {
        var obj = initApp()
        fmt.Println(obj)
    }