首页 文章

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

提问于
浏览
71

在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 ,就像我在第一个例子中必须做的那样;它似乎不一致 . 我确信这是有充分理由的;任何人都可以开导我吗?

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

2 回答

  • 12

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

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

    我不知道的相关区别是 namedunnamed 类型 .

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

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

    如果比较两个命名类型,则名称必须匹配才能使它们可互换 . 如果你比较一个命名和一个未命名的类型,然后 as long as the underlying representation matches ,你很高兴去!

    例如给出以下类型:

    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)
    

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

  • 124

    问题和答案都非常具有启发性 . 但是,我想提出一个区别,这在lytnus的回答中并不清楚 .

    • Named TypeUnnamed Type 不同 .

    • Named Type 的变量可分配给 Unnamed Type 的变量,反之亦然 .

    • 不同 Named Type 的变量不能彼此分配 .

    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
    }
    

相关问题