Goはnilポインタからメソッドを呼び出す事が出来ます。呼び出した際の挙動について確認して行きます。
ポインタレシーバメソッド呼び出し
nilポインタからポインタレシーバのメソッドを呼び出す事が出来ます。
package main
import (
"fmt"
)
// 構造体定義
type myStruct struct {
name string
}
// メソット定義
func (m *myStruct) greet() {
fmt.Println("ハロー")
}
func main() {
var m *myStruct // ポインタ型のゼロ値のnilになる。
m.greet() // ハロー が表示される。
}
nilポインタの注意点
nilポインタの場合、フィールドを参照する事はできません。
package main
import (
"fmt"
)
// 構造体定義
type myStruct struct {
name string
}
// メソット定義
func (m *myStruct) greet() {
fmt.Println(m.name) // 実行するとパニックになります。
}
func main() {
var m *myStruct // ポインタ型のゼロ値のnilになる。
m.greet()
}
nil判定
ポインタ型がポインタレシーバのメソッドを呼び出した場合、メソッド内でレシーバの値がnilかどうかを判定出来ます。ポインタ型のゼロ値はnilなので、レシーバをnil判定できるようになります。
package main
import (
"fmt"
)
// 構造体定義
type myStruct struct {
name string
}
// メソット定義
func (m *myStruct) setName(name string) {
m.name = name
}
func (m *myStruct) getName() string {
if m == nil {
return "名前を設定して下さい"
}
return m.name
}
func main() {
var m *myStruct // ポインタ型のゼロ値のnilになる。
fmt.Println(m.getName()) // 名前を設定して下さい が表示される。
}
なお、宣言する構造体インスタンスをポインタ型に指定しない場合、nil判定されません。
package main
import (
"fmt"
)
// 構造体定義
type myStruct struct {
name string
}
// メソット定義
func (m *myStruct) setName(name string) {
m.name = name
}
func (m *myStruct) getName() string {
if m == nil {
return "名前を設定して下さい"
}
return m.name
}
func main() {
var m myStruct // 構造体インスタンスとして宣言。
fmt.Println(m.getName()) // 何も表示されない。
}
値レシーバメソッド呼び出し
nilポインタから値レシーバのメソッドを呼び出すとパニックになります。
package main
import (
"fmt"
)
// 構造体定義
type myStruct struct {
name string
}
// メソット定義
func (m myStruct) greet() {
fmt.Println("ハロー")
}
func main() {
var m *myStruct
m.greet() // パニックが発生する。
}