🫥

「インタフェースがnilであれば、それに関するどのメソッドを起動してもパニックになる」の意味

2025/01/03に公開

O'Reilly の初めてのGo言語の文章がしっくりこない

インタフェースがnilであるかどうかは、そのインタフェースに関するメソッドを起動できるかどうかを示すことになります。前に説明したように、具象型のインスタンスがnilであっても、それに関するメソッドを呼び出すことができますから、nilの具象インスタンスを代入されたインタフェース変数に関するメソッドを起動できるのは問題がありません。インタフェースがnilであれば、それに関するどのメソッドを起動してもパニックになります。インタフェースが非nilならば、それに関するメソッドを起動できます(ただし、値がnilの場合、割り当てられた型のメソッドがnilをきちんと処理できなければ、やはりパニックになります)。

と書いてあり、「インタフェースがnilであれば、それに関するどのメソッドを起動してもパニックになります。」の部分がしっくりこなかったので動かして理解してみた

一旦手を動かしてみる

interfaceと基底型をnilで定義して、メソッドを実行してみる

package main

import (
   "fmt"
)

// サンプルのインターフェース
type MyInterface interface {
   Method()
}

// 実装構造体
type MyStruct struct{}

func (m *MyStruct) Method() {
   fmt.Println("Method called!")
}

func main() {
   var ms *MyStruct
   fmt.Println(ms == nil) // true
   var i MyInterface      // interface{}の代わりにanyでも同じ
   fmt.Println(i == nil)  // true
   i = ms
   i.Method()
}
//--------------------------------
true
true
false
Method called!

panicせず普通にMethod()が実行できてしまう・・・

そもそも文中しっくりこなかった「インタフェースがnil」とは

インタフェースは「ベースとなる型(基底型)へのポインタ」と「ベースとなる値へのポインタ」の組で実装されています。型が非nilならば、インタフェースはnilにはなりません

インタフェースがnilであるとみなされるためには、型と値の両方がnilでなければなりません

と書いてありました。

また、この文章の近くにあったサンプルコードが下記で

var s *string
fmt.Println(s == nil) // true
var i interface{}  // interface{}の代わりにanyでも同じ
fmt.Println(i == nil) // true
i = s
fmt.Println(i == nil) // false

ベースとなる型(基底型)(*string)も、ベースとなる値(s)へのポインタもnilなのに、siに代入するとnilでなくなっています。

これは、i = s のように具体的な値を代入し、
型情報: *string(ベースとなる型)
値情報: s の値
が入り、snilなので値の情報は入っていないとして、
型の情報が入っており、インタフェースがnilであるとみなされるためには、型と値の両方がnilでなければならない ので、inilではなくなっているということ

つまり、どうしたらpanicになるかというと

冒頭でしっくりこなかった「インタフェースがnilであれば、それに関するどのメソッドを起動してもパニックになります。」という文章をコードにすると多分下記で

package main

import (
	"fmt"
)

// サンプルのインターフェース
type MyInterface interface {
	Method()
}

func main() {	
	var i MyInterface      // interface{}の代わりにanyでも同じ
	fmt.Println(i == nil)  // true
	i.Method()
}

ただinterfaceのMethod()を実行するとpanicになる。
そりゃそうって話ではありますが、

  • インタフェースは「ベースとなる型(基底型)へのポインタ」と「ベースとなる値へのポインタ」の組で実装されている
  • インタフェースがnilであるとみなされるためには、型と値の両方がnilでなければならない

ので、この場合のinterfaceはnilになり、panicを起こす、ということが学びになりました。

Discussion