问题提出

考察以下代码:

//定义两个自定的类型
type MyInt int
type MyFunc func(arg int)

//定义两个函数,其参数类型为上述类型
func myFunc(arg MyInt) {
    fmt.Println("myFunc() is called")
}
func myFunc2(arg MyFunc) {
    arg(0)
    fmt.Println("myFunc2() is called")
}

func main() {
    var a = int(32)
    var b = func(arg int) {
        fmt.Println("arg = ", arg)
    }
    
    myFunc(a) //编译错误,不能使用int类型作为 myFunc 函数的参数,因为 myFunc 函数的参数类型为 MyInt
    myFunc2(b) //可以运行,即使 myFunc2接收的参数类型是 MyFunc,而 b 的类型是 func(int)
}

问题解决

Go 语言的 Specification中有提到关于类型的同一性的问题,这里面有一个我没有意识到的差别:命名类型匿名类型

命名类型是指那些有名字的类型,比如 intint64floatstringbool等,还有,所有你用type关键字定义出来的自定义的类型都属于命名类型

匿名类型是那些[]stringmap[string]string[4]int。它们没有名字,只是简单的描述了它们需要怎样的结构

如果你要比较两个命名的类型,这两个类型的类型名必须要一致,例如:

type MyInt int

var i int = 2
var i2 MyInt = 4
i = i2	//错误,因为 i 是命名类型 int, i2是命名类型 MyInt

而如果是一个命名类型与匿名类型做比较,那么只要两个类型的底层数据结构一致即可,例如:

type MyMap map[string]int

m := make(map[string]int)
var m2 MyMap = m //正确,因为 map[string]int 是匿名类型