We’ll cover the last 3 rules of selectors in one go today, since they’re all about illegal selectors.
Selectors
…
- In all other cases,
x.f
is illegal.
Simple enough. The cases mentioned in rules 1-3 ar ethe only valid uses of x.f
. All others are illegal.
var x int
x.chicken // illegal!
- If
x
is of pointer type and has the valuenil
andx.f
denotes a struct field, assigning to or evaluatingx.f
causes a run-time panic.
var x *Person // x is of type *Person, but has the default value of `nil`
fmt.Println(x.Name) // panic: runtime error: invalid memory address or nil pointer dereference
- If
x
is of interface type and has the valuenil
, calling or evaluating the methodx.f
causes a run-time panic.
var x interface { // is an interface type, but has the default value of `nil`
Foo()
}
x.Foo() // panic: runtime error: invalid memory address or nil pointer dereference
The spec then offers its own examples, which I won’t go over, as I’ve already covered most these cases (and more) with my own commentary.
For example, given the declarations:
type T0 struct { x int } func (*T0) M0() type T1 struct { y int } func (T1) M1() type T2 struct { z int T1 *T0 } func (*T2) M2() type Q *T2 var t T2 // with t.T0 != nil var p *T2 // with p != nil and (*p).T0 != nil var q Q = p
one may write:
t.z // t.z t.y // t.T1.y t.x // (*t.T0).x p.z // (*p).z p.y // (*p).T1.y p.x // (*(*p).T0).x q.x // (*(*q).T0).x (*q).x is a valid field selector p.M0() // ((*p).T0).M0() M0 expects *T0 receiver p.M1() // ((*p).T1).M1() M1 expects T1 receiver p.M2() // p.M2() M2 expects *T2 receiver t.M2() // (&t).M2() M2 expects *T2 receiver, see section on Calls
but the following is invalid:
q.M0() // (*q).M0 is valid but not a field selector
Quotes from The Go Programming Language Specification Version of August 2, 2023