レシーバがnilの場合の対応について以下のように記述がある。
ポインタ型のレシーバは関数の引数にポインタを渡す場合と同じ用に動作します。メソッドに渡されるのはポインタのコピーなのです。関数にnilが渡された場合と同様、コピーのポインタを変更しても、オリジナルは変更されません。つまり、nilを受け取ってnilではないものに変更するようなポインタレシーバは書けません
以下のように書いてみる
func (n *Node) InitIfNil() {
if n == nil {
n = &Node{} // ★ ここでレシーバ変数だけが別の番地を持つ
}
}
list := (*Node)(nil)
list.InitIfNil()
fmt.Println(list == nil) // -> true (呼び出し側は変わらない)
コード中に記載したようにメソッドの呼び出し時にポインタをコピーして実行しているので、メソッドの中でポインタを変更しても呼び出し側には影響がない。
どうしても変更したいような場合には以下のようにポインタのポインタを利用する
func Init(pp **Node) {
if *pp == nil {
*pp = &Node{}
}
}
var list *Node = nil
Init(&list)
このように元のポインタ変数へのポインタ(**Node
)を引数に取れば元のポインタ変数を直接触れるのでnil -> 非nilに変更出来る。
ただし、Go言語においてメソッドのレシーバ型に許されるのは T か *T のみとなるため、メソッドを使う場合この手法は有効でない。