型アサーションはインターフェース値から具体的な型を抽出し、型スイッチはインターフェースの基礎となる型で分岐します。これらはインターフェース(特に空のインターフェース / any)から特定の型情報を取り戻す方法です。
型アサーション — 具体的な型を抽出する
i {} =
s := i.()
fmt.Println(s)
n := i.()
i.(Type) シンタックスはインターフェース i が Type の値を保持していることをアサートして、それを抽出します。しかし、間違ったアサーションはパニックを起こします。そのため、通常はセーフなカンマ-オケー形式を使用します。
s, ok := i.(string)
if ok {
fmt.Println("it's a string:", s) // ok = true, s = the value
} else {
fmt.Println("not a string") // ok = false, s = zero value, NO panic
}
2つの値を返す形式は、値とブール値を返します。アサーションが失敗した場合、ok は false になります(パニックの代わりに)。常にこの形式を優先してください。型が確実な場合を除きます。
func describe(i interface{}) string {
switch v := i.(type) { // the special .(type) form, only in a switch
case int:
return fmt.Sprintf("int: %d (doubled: %d)", v, v*2)
case string:
return fmt.Sprintf("string of length %d", len(v))
case bool:
return fmt.Sprintf("bool: %t", v)
case nil:
return "nil value"
default:
return fmt.Sprintf("unknown type: %T", v)
}
}
describe(42) // "int: 42 (doubled: 84)"
describe("hi") // "string of length 2"
switch v := i.(type) 形式は基礎となる型をチェックし、各ケースで v を適切に型指定して束縛します。複数の型を保持する可能性があるインターフェースを処理するきれいな方法です。
// assert that a value implements a specific interface
if w, ok := i.(io.Writer); ok {
w.Write([]byte("data")) // use it as an io.Writer if it satisfies that interface
}
✓ Processing values of unknown type (interface{}/any) — JSON, generic handlers
✓ Checking if a value implements an optional interface (e.g. io.Closer)
✓ Handling heterogeneous data
⚠️ Often a sign you could use generics or better-typed interfaces instead — don't overuse
型アサーションと型スイッチはインターフェース値を扱うための重要なツールです。interface{}/any から具体的な型情報を取り戻したり、値が特定のインターフェースを満たしているかをチェックしたりするために必要です。
これらは未知の型または多様な型のデータを処理する場合に必要です(動的 JSON の解析、汎用的な処理、オプショナルインターフェースチェック(例えば「これは io.Closer を実装していますか?」)など)。
パニック対セーフな区別を理解することは重要です。プレーンなアサーション i.(T) は不一致でパニックしますが、カンマ-オケー形式 v, ok := i.(T) は安全に失敗を報告します。セーフな形式を使うことはランタイムクラッシュを避けるための重要な実践です。
型スイッチは複数の可能な型を優雅に処理します。
これらを知ること(そして多量の使用が、代わりにジェネリクスまたはより良く型指定された設計に頼るべきであることを示していることを含む)は、安全で慣用的な Go のために重要です。また、インターフェースと空のインターフェースが言語の中心であるため、一般的なインタビューのトピックでもあります。