Go allows simplified forms of some selectors.
For example, in the following program, t1.M1
is a simplified form of (*t1).M1
,
and t2.M2
is a simplified form of (&t2).M2
. At compile time, the compiler will normalize the simplified forms to their original respective full forms.
The following program prints 0
and 9
, because the modification to t1.X
has no effects on the evaluation result of *t1
during evaluating (*t1).M1
.
package main
type T struct {
X int
}
func (t T) M1() int {
return t.X
}
func (t *T) M2() int {
return t.X
}
func main() {
var t1 = new(T)
var f1 = t1.M1 // <=> (*t1).M1
t1.X = 9
println(f1()) // 0
var t2 T
var f2 = t2.M2 // <=> (&t2).M2
t2.X = 9
println(f2()) // 9
}
In the following code, the function foo
runs okay, but the function bar
will produce a panic. The reason is s.M
is a simplified form of (*s.T).M
. At compile time, the compiler will normalize the simplified form to it original full form. At runtime, if s.T
is nil, then the evaluation of *s.T
will cause a panic. The two modifications to s.T
have no effects on the evaluation result of *s.T
.
package main
type T struct {
X int
}
func (t T) M() int {
return t.X
}
type S struct {
*T
}
func foo() {
var s = S{T: new(T)}
var f = s.M // <=> (*s.T).M
s.T = nil
f()
}
func bar() {
var s S
var f = s.M // panic
s.T = new(T)
f()
}
func main() {
foo()
bar()
}
Please note that, interface method values and method values got through reflection
will be expanded to the promoted method values with a delay.
For example, in the following program, the modification to s.T.X
has effects on the method values got through reflection and interface ways.
package main
import "reflect"
type T struct {
X int
}
func (t T) M() int {
return t.X
}
type S struct {
*T
}
func main() {
var s = S{T: new(T)}
var f = s.M // <=> (*s.T).M
var g = reflect.ValueOf(&s).Elem().
MethodByName("M").
Interface().(func() int)
var h = interface{M() int}(s).M
s.T.X = 3
println( f() ) // 0
println( g() ) // 3
println( h() ) // 3
}