In the "Pointers vs. Values" section of Effective Go, it states that "value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers." This is due to the fact that pointer methods can modify the receiver, and invoking them on a copy of the value would cause these modifications to be discarded.
However, some developers have encountered a situation where they were able to invoke a pointer method on a value, which seemingly contradicts the documented syntax rules. To clarify this confusion, we will explore this behavior in more detail.
Consider the following Go code:
<code class="go">package main import ( "fmt" "reflect" ) type age int func (a age) String() string { return fmt.Sprintf("%d yeasr(s) old", int(a)) } func (a *age) Set(newAge int) { if newAge >= 0 { *a = age(newAge) } } func main() { var vAge age = 5 pAge := new(age) fmt.Printf("TypeOf =>\n\tvAge: %v\n\tpAge: %v\n", reflect.TypeOf(vAge), reflect.TypeOf(pAge)) fmt.Printf("vAge.String(): %v\n", vAge.String()) fmt.Printf("vAge.Set(10)\n") vAge.Set(10) fmt.Printf("vAge.String(): %v\n", vAge.String()) fmt.Printf("pAge.String(): %v\n", pAge.String()) fmt.Printf("pAge.Set(10)\n") pAge.Set(10) fmt.Printf("pAge.String(): %v\n", pAge.String()) }</code>
In this example, we define a age type with two methods: String() (value method) and Set() (pointer method). The code creates two variables: vAge, a value of type age, and pAge, a pointer to an age value.
Despite the documentation indicating that vAge.Set() should not be valid syntax, the code compiles without errors. This is because vAge is addressable, meaning it has a memory address that can be referenced. As per the language specification, a method call x.m() on an addressable variable x is valid if x's method set contains m.
In this case, vAge is addressable, and since the method set of *age contains Set(), the call vAge.Set() is shorthand notation for (&vAge).Set(). Essentially, the & operator is being used implicitly to obtain the pointer to vAge.
Therefore, the code demonstrates that value methods can indeed be invoked on pointers because invoking them on an addressable value is equivalent to calling the method on a pointer to that value. The pointer method Set() is still only invocable on pointers, but in the case where the value is addressable, the implicit dereferencing allows for the syntax vAge.Set() to be valid.
The above is the detailed content of ## Why Can I Call a Pointer Method on a Value in Go?. For more information, please follow other related articles on the PHP Chinese website!