Go The syntax for calling a function with a pointer pointer

In Go, if I define a function with a pointer as a receiver, shouldn't I only allow the function to be called from the pointer? Why is it okay to call this function from the value itself and have the same effect.

For example, in the following program: m1.reset () and m2.reset () have the same effect. Although m1 is a value and m2 is a pointer.

I'm a little confused because there are two ways to do the same and I'm not sure which one should be followed. Although most of the code follows the convention of calling a function using a pointer field. Did I miss something?

package main

    import "fmt"

    type MyStruct struct {
        X int
    }

    func (m *MyStruct) reset() {
        m.X = 0
    }

    func main() {
        m1 := MyStruct{1}
        m2 := &MyStruct{1}

        fmt.Println(m1.X)
        fmt.Println(m2.X)

        m1.reset()
        m2.reset()

        fmt.Println(m1.X)
        fmt.Println(m2.X)
    }

      

+3


source to share


3 answers


The specialist says :

The set of methods of the corresponding pointer type * T is the set of all methods with the receiver * T or T (that is, it also contains the set of methods T).

The next piece of required call information says:



The method call is x.m()

valid if the method set (type) x contains m, and the argument list can be assigned to the parameter list m. If x is addressable and the method set & x contains m, x.m()

is shorthand for (&x).m()

.

Combine the above two and you get the behavior you see.

+4


source


@jnml offers a perfect explanation of the document spec, but I wanted to add some sample code based on yours. I think your focus should be less about "Why are there two ways to do the same thing" and more about when to use one against the other. A method that has a pointer as a receiver has the ability to change the values โ€‹โ€‹of that receiver, whereas a method that has a value as a receiver cannot. This is because the methods receive a copy of the receiver. When you get a copy of a pointer, you can still change its value. When you get a copy of the value, the changes you make in this method only change the copy, not the original:

package main

import "fmt"

type MyStruct struct {
    X int
}

func (m *MyStruct) resetPtr() {
    m.X = 0
}

func (m MyStruct) resetValue() {
    m.X = 0
}

func main() {
    m1 := MyStruct{1}
    m2 := &MyStruct{1}

    fmt.Println("Original Values:", m1.X, m2.X)

    m1.resetPtr()
    m2.resetPtr()

    fmt.Println("After resetPtr():", m1.X, m2.X)

    m1 = MyStruct{1}
    m2 = &MyStruct{1}

    m1.resetValue()
    m2.resetValue()

    fmt.Println("After resetValue():", m1.X, m2.X)
}

      

Output



Original Values: 1 1
After resetPtr(): 0 0
After resetValue(): 1 1

      

You can see that the way these variables are accessed is not a problem. It's more about what you can do with them inside a method, and how they are passed as arguments to other functions or methods (copied).

+9


source


The short explanation is that the Go compiler behind the scenes automatically converts:

m1.reset()
m2.reset()

      

in

(&m1).reset()
m2.reset()

      

+2


source







All Articles