golangの日記

Go言語を中心にプログラミングについてのブログ

Go言語(golang)のinterface{}を型アサーション/型キャスト

golang.png


アサーション(assertion)の意味は断定、断言なので、型を断定するですかね。

interface型をアサートするには、i.(T) を使います。
複数から判別したい場合は、switch文で i.(type) を使います。
構造体type xxx structやインターフェースtype xxx interface についても同様です。







インターフェース型にする

// 1
var i interface{}
i = true

// 2
var i interface{} = 100

// 3
i := interface{}("hello")



型アサーション

以下のようにすると、変数 s は文字列型になります。

func main() {
    i := interface{}("hello")
    s := i.(string)
}


型が間違っていると、パニックする

func main() {
    i := interface{}("hello")
    s := i.(int) // panic!
}


パニックしないように型が合っているかどうかを確認するには、
2つめの変数を受け取り、その真偽値で判定できます。

以下の型が間違っている変数 n はint型でゼロ値になる

func main() {
    i := interface{}("hello")

    n, ok := i.(int)
    fmt.Println(n, ok) // 0  false
    
    s, ok := i.(string)
    fmt.Println(n, ok) // hello  true
}



switchで複数から判別する

i.(type) はswitch文のみで使うことができます。

package main

func main() {
    i := interface{}(100)

    switch i.(type) {
    case string:
        s := i.(string)
        println("i is string:", s)
    case bool:
        b := i.(bool)
        println("i is boolean:", b)
    case int:
        n := i.(int)
        println("i is integer:", n) // i is integer: 100
    }
}


細かく判別できる

package main

func main() {
    var v int64 = 100
    i := interface{}(v)

    switch i.(type) {
    case int32:
        println("int32")
    case int16:
        println("int16")
    case int64:
        println("int64") // int64
    }
}



構造体(struct)

type struct も同じように変換できる

package main

type A struct{}

func main() {
    i := interface{}(A{})
    _, ok := i.(A)

    println("A:", ok)
}



インターフェース(interface)

type interface で定義した要件を満たしているかどうかの判別にも i.(T) が使えます。

package main

type A struct {
}

type B struct {
}

func (b B) Hello(name string) {
    println("hello", name)
}

type Interface interface {
    Hello(name string)
}

func main() {
    var ok bool

    // A の構造体は Hello メソッドを持っていないので false
    a := interface{}(A{})
    _, ok = a.(Interface)
    println("A:", ok) // A: false

    // B の構造体は Hello メソッドを持っているので true
    b := interface{}(B{})
    _, ok = b.(Interface)
    println("B:", ok) // B: true
}


この具体例が、Go言語のflagパッケージの929行目にあって type boolFlag interface かどうかを判定してます。
https://golang.org/src/flag/flag.go#L929