Wen

Golangでは暗黙的な型変換もあることを知ってた?

N views

環境

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で新たに定義された方です。

そうすると、m1m2 はお互いに代入できることは明白ですが、

    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以外にboolstring などの predeclared type が全て defined type (派生型)になるようです。

参考記事

入門 Go 言語仕様 Underlying Type / Go Language Underlying Type
惊了!原来 Go 语言也有隐式转型

Credits

Photo by Chinmay Bhattar

本記事は 「表示 - 非営利 - 改変禁止 4.0 国際 (CC BY-NC-ND 4.0)」 を採用。