インタフェース型の変数が特定の具象型を持っているか、あるいはその具象型が別のインタフェースを実装しているかを調べるのに、Goには2つの方法がある。

7.11.1 型アサーション

  • 型アサーションは実行時にチェックされ、カンマ ok イディオムでチェックしないとパニックを引き起こす危険性がある
  type MyInt int
  
  func main() {
  	var i any
  	var mine MyInt = 20
  	i = mine  // mineの型はMyInt。iはanyなので代入できる
  	i2 := i.(int) // iに代入された型はMyIntなので、パニック!
  	fmt.Println(i2)
  }
  • そのため、型アサーションに間違いがないと確信していても、カンマ ok イディオムを使用することを推奨
type MyInt int
 
func main() {
	var i any
	var mine MyInt = 20
	i = mine
	i2, ok := i.(int)
	if !ok {
		err := fmt.Errorf("iの型(値:%v)が想定外です", i)
		fmt.Println(err.Error())
		os.Exit(1) // プログラムを終了
	}		
	fmt.Println(i2)
}

7.11.2 型switch

型switchはインタフェースが複数の型のいずれかである場合に使用する

func doThings(i any) {
	switch j := i.(type) {
	case nil: // iはnil。jの型はany
		fmt.Printf(" case nil; i:%v(型:%T), j:%v(型:%T\n", i, i, j, j)
	case int: // jの型はint
		fmt.Printf(" case int; i:%d(型:%T), j:%v(型:%T\n", i, i, j, j)
	case MyInt: // jの型はMyInt
		fmt.Printf(" case MyInt; i:%d(型:%T), j:%v(型:%T\n", i, i, j, j)
	case io.Reader: // jの型はio.Reader
		fmt.Printf(" case io.Reader; i:%v(型:%T), j:%v(型:%T\n", i, i, j, j)
	case string: // jは文字列
		fmt.Printf(" case string; i:%s(型:%T), j:%v(型:%T\n", i, i, j, j)
	case bool, rune: // iはboonかruneなので、jの型はany
		fmt.Printf(" case bool, rune; i:%v(型:%T), j:%v(型:%T\n", i, i, j, j)
	default: // iの型は不明。jの型はany
		fmt.Printf(" default; i:%v(型:%T), j:%v(型:%T\n", i, i, j, j)
	}
}