なぜエイリアス関数を入力してキャストせずに使用できるのですか?


97

Goで、新しいタイプを定義する場合:

type MyInt int

その後MyInt、intを期待する関数にa を渡すことはできません。逆も同様です。

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にtype MyFuncにキャストする必要がなくなるため、不満はありません。一貫性がないようです。それには十分な理由があると私は確信しています。誰かが私を啓発できますか?

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


typeGoではScalaよりもかなり便利です。Scalaには型エイリアスしかありません
Rick-777

4
Goは実際にはタイプエイリアスgithub.com/golang/go/issues/18130
Hut8

誰かが2番目のコードスニペットを説明できますか?私はそれらの関数宣言を本当に手に入れることができません
DevX 2018年

回答:


148

結局のところ、これは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)

私はすぐにそれを知らなかったので少し気が抜けたので、誰かのためにタイプラークを少し明確にしたいと思います!そして、私が最初に思ったよりもはるかに少ないキャストを意味します:)


1
is := make(MySlice, 0); m := make(MyMap)一部のコンテキストではより読みやすいを使用することもできます。
R2B2 2018年

13

質問と答えの両方がかなり啓発的です。しかし、lytnusの答えでは明確ではない区別を取り上げたいと思います。

  • 名前付きタイプは、名前なしタイプとは異なります。

  • 変数の名前付きタイプの変数に割り当て可能です。名前タイプ、その逆。

  • 異なる名前付きタイプの変数は相互に割り当てることができません。

http://play.golang.org/p/uaYHEnofT9

import (
    "fmt"
    "reflect"
)

type T1 []string
type T2 []string

func main() {
    foo0 := []string{}
    foo1 := T1{}
    foo2 := T2{}
    fmt.Println(reflect.TypeOf(foo0))
    fmt.Println(reflect.TypeOf(foo1))
    fmt.Println(reflect.TypeOf(foo2))

    // Output:
    // []string
    // main.T1
    // main.T2

    // foo0 can be assigned to foo1, vice versa
    foo1 = foo0
    foo0 = foo1

    // foo2 cannot be assigned to foo1
    // prog.go:28: cannot use foo2 (type T2) as type T1 in assignment
    // foo1 = foo2
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.