Go 言語では暗黙的な型キャストは許されていません。明示的な型変換関数を使用するか、Type Assertion という仕組みを使用して型の変換を行う必要があります。
型キャスト
Go 言語では暗黙的な型変換は許されていないため、下記のような異なる型の変数への代入はコンパイルエラーになります。
var i int = 100
var f float64 = i // cannot use i (type int) as type float64
このようなケースでは、型名(値)
という形で明示的な 型キャスト を行います。
var i int = 100
var f float64 = float64(i) // OK
下記は様々な型変換の例です。
型アサーション (Type Assertion) による型変換
Go 言語で任意の型の変数(型の定まっていない変数)は、空インタフェース型 (interface{}
) として表現されます。
このような値を、特定の型 T
の変数に代入するには、型アサーション (Type Assertion) という仕組みを使用する必要があります。
型アサーションは、下記のような構文で実行します。
var x = i.(T)
x := i.(T) // 関数内であればこの省略形で OK
これにより、空インタフェース型 (interface{}
) の変数 i
が、型 T
の変数 x
に代入されます。
空インタフェース型の i
を、型 T
に変換できない場合は パニック が発生します。
下記の doGreet
関数は、パラメータで受け取った任意の型のオブジェクトに対して、Greet
メソッドを実行します。
空インタフェースは Greet
メソッドを備えていないので、まずは、i.(Greeter)
という型アサーションで Greeter
型に変換してから Greet
メソッドを呼び出しています。
type Greeter interface {
Greet()
}
func doGreet(i interface{}) {
g := i.(Greeter)
g.Greet()
}
上記の doGreet
関数は、Greet()
メソッドを実装したオブジェクトを渡された場合にうまく動作します。
下記のサンプルでは、Greet()
メソッドを実装した People
構造体のオブジェクトを、doGreet
関数に渡しています。
type People struct {
Name string
}
func (this *People) Greet() {
fmt.Printf("Hello, I am %s\n", this.Name)
}
func main() {
p := &People{"Maku"}
doGreet(p) //=> "Hello, I am Maku"
}
逆に、Greet()
メソッドを実装していないオブジェクトを doGreet
関数に渡すと、型アサーションによる型変換に失敗し、パニックが発生します。
doGreet("Hoge") // panic: interface conversion:
// string is not main.Greeter: missing method Greet
このように、実際に実行するまでパニックが発生するかどうか分からないような関数は、安心して実行することができません。 そこで、型アサーションには、型変換がうまくいったかどうかを調べる構文が用意されています(マップ のキーの有無を確認する構文と同じです)。
x, ok := i.(T)
上記のように、2 つの戻り値を受け取るように型アサーションを実行すると、2 番目の戻り値 (bool) で、型変換に成功したかどうかを判別することができます。
型変換に失敗してもパニックは発生せず、x
には型 T
のゼロ値が格納されます。
下記の doGreet
関数は、渡された interface{}
オブジェクトを Greeter
型に変換できるか確認し、変換できた場合のみ Greet()
メソッドを呼び出しています。
func doGreet(i interface{}) {
if g, ok := i.(Greeter); ok {
g.Greet()
} else {
fmt.Printf("Type %T is not Greeter\n", i)
}
}
func main() {
doGreet(&People{"Maku"}) //=> Hello, I am Maku
doGreet(100) //=> Type int is not Greeter
doGreet(0.5) //=> Type float64 is not Greeter
doGreet("Hoge") //=> Type string is not Greeter
}
ちなみに、より多くの型への型変換を試みなければならないケース (Printf
のような関数の実装)では、型スイッチの構文 を使用するとより簡潔に記述することができます。