为什么我可以键入别名函数并使用它们而不进行转换?

jsd*_*sdw 86 types casting go

在Go中,如果您定义一个新类型,例如:

type MyInt int
Run Code Online (Sandbox Code Playgroud)

然后,您无法将a传递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
}
Run Code Online (Sandbox Code Playgroud)

精细.但是为什么同样不适用于功能呢?例如:

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
}
Run Code Online (Sandbox Code Playgroud)

现在,我没有抱怨,因为它节省了我必须明确地转换newfunc为类型MyFunc,正如我在第一个例子中必须做的那样; 它似乎不一致.我确信这是有充分理由的; 任何人都可以开导我吗?

我问的原因主要是因为我想以这种方式缩短我的一些相当长的函数类型,但我想确保它是预期的并且可以接受这样做:)

jsd*_*sdw 141

事实证明,这是一个关于Go如何处理类型的误解,可以通过阅读规范的相关部分来解决:

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

我不知道的相关区别是命名未命名类型.

命名类型是具有名称的类型,例如int,int64,float,string,bool.此外,使用"type"创建的任何类型都是命名类型.

未命名的类型是诸如[] string,map [string] string,[4] int之类的.它们没有名称,只是描述了它们的结构.

如果比较两个命名类型,则名称必须匹配才能使它们可互换.如果您比较命名和未命名类型,那么只要基础表示匹配,您就可以开始了!

例如,给出以下类型:

type MyInt int
type MyMap map[int]int
type MySlice []int
type MyFunc func(int)
Run Code Online (Sandbox Code Playgroud)

以下内容无效:

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

以下是好的:

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)
Run Code Online (Sandbox Code Playgroud)

我有点内疚,我早就不知道了,所以我希望能为别人澄清类型百灵!并且意味着比我最初认为的铸造少得多:)

  • 你也可以使用`is := make(MySlice, 0); m := make(MyMap)`,在某些情况下更具可读性。 (2认同)

Min*_*gyu 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
}
Run Code Online (Sandbox Code Playgroud)