🔥
Golangでは暗黙的な型変換もあることを知ってた?
環境
Go version: go1.17.8
コード
下記のコードにあるように、
明示的に変換しないとエラーになるタイプ (int
) と
変換せずにそのまま代入できるタイプ (map[string]int
) があることがわかります。
package main
import (
"fmt"
"runtime"
)
type MyInt int
type MyMap map[string]int
func main() {
fmt.Printf("Go version: %s\n", runtime.Version())
var x MyInt
var y int
x = y // コンパイルエラー: cannot use y (type int) as type MyInt in assignment
var m1 MyMap
var m2 map[string]int
m1 = m2 // OK
m2 = m1 // OK
}
理由
Golang の仕様書の 代入可能性(Assignability) のところでちゃんと書いてありました。
x's type V and T have identical underlying types and at least one of V or T is not a defined type.
a と b が同一のunderlying type (基底型、背後霊的な型 w)を持ち、
a または b の少なくとも一方が defined type (派生型)でないなら、お互い代入可能のようです。
派生型は名前の通りで、別の型からtype
で新たに定義された方です。
そうすると、m1
と m2
はお互いに代入できることは明白ですが、
var m1 MyMap
var m2 map[string]int
m1 = m2 // OK
m2 = m1 // OK
変数 | 基底型 | 派生型? |
---|---|---|
var m1 MyMap | map[string]int | Yes |
var m2 map[string]int | map[string]int | No |
問題はMyInt
ですね。
var x MyInt
var y int
x = y // コンパイルエラー: cannot use y (type int) as type MyInt in assignment
変数 | 基底型 | 派生型? |
---|---|---|
var x MyInt | int | Yes |
var y int | int | No じゃなかった! ← ここ重要 |
int
は 一見派生型じゃないように見えますが、
実は Golang の都合上、ソースコードにあるように、int
も(自分自身の...)派生型になります。
type int int
ちなみに、上記のリンク先にあるように、
int
以外にbool
、string
などの predeclared type が全て defined type (派生型)になるようです。
参考記事
入門 Go 言語仕様 Underlying Type / Go Language Underlying Type
惊了!原来 Go 语言也有隐式转型
Discussion