1. ホーム
  2. types

[解決済み] なぜエイリアス関数をタイプして、キャストせずに使用できるのですか?

2022-05-16 20:39:18

質問

Goでは、新しい型を定義する場合、例えば

type MyInt int

を渡すことはできません。 MyInt をintを期待する関数に渡したり、その逆もできません。

func test(i MyInt) {
    //do something with i
}

func main() {
    anInt := 0
    test(anInt) //doesn't work, int is not of type MyInt
}

結構です。しかし、それではなぜ関数に同じことが適用されないのでしょうか? 例を挙げます。

type MyFunc func(i int)
func (m MyFunc) Run(i int) {
    m(i)
}

func run(f MyFunc, i int) {
    f.Run(i)
}

func main() {
    var newfunc func(int) //explicit declaration
    newfunc = func(i int) {
        fmt.Println(i)
    }
    run(newfunc, 10) //works just fine, even though types seem to differ
}

さて、文句を言っているわけではありません。 newfunc をタイプするために MyFunc と入力しなければなりませんが、これは矛盾しているように思えます。きっと何か理由があるのでしょうが、どなたか教えていただけませんか?

私が尋ねる理由は、主に、この方法でかなり長い関数型のいくつかを短くしたいからです。しかし、これを行うことが期待され受け入れられるかどうかを確認したいのです :)

どのように解決するのですか?

これは、Go がどのように型を扱うかについて私が持っていた誤解であることがわかりました。これは、仕様の関連する部分を読むことで解決できます。

http://golang.org/ref/spec#Type_identity

私が知らなかった関連する区別は、次のようなものでした。 という名前です。 無名 の型があります。

名前付き 型はint, int64, float, string, boolのような名前を持つ型です。また、'type'を使って作成した型はすべて名前付き型です。

無名 型は[]string, map[string]string, [4]intのようなものです。これらは名前を持たず、単にそれらがどのように構造化されるかに対応する記述を持っています。

2つの名前付き型を比較する場合、交換可能であるために名前が一致しなければなりません。もし名前付きの型と名前なしの型を比較するのであれば が一致する限り であれば、問題ありません。

例えば、以下のような型があるとします。

type MyInt int
type MyMap map[int]int
type MySlice []int
type MyFunc func(int)

は無効です。

var i int = 2
var i2 MyInt = 4
i = i2 //both named (int and MyInt) and names don't match, so invalid

は、以下でよい。

is := make([]int)
m := make(map[int]int)
f := func(i int){}

//OK: comparing named and unnamed type, and underlying representation
//is the same:
func doSlice(input MySlice){...}
doSlice(is)

func doMap(input MyMap){...}
doMap(m)

func doFunc(input MyFunc){...}
doFunc(f)

私はもっと早くそれを知らなかったので、少しがっかりしています。そして、私が最初に考えたよりずっと少ない鋳造を意味します :)