Why can I type alias functions and use them without casting?

在 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类型,就像我在第一个示例中必须做的那样; 它只是看起来不一致。我肯定这是有原因的,有人能给我解释一下吗?

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

57579 次浏览

原来,这是我对围棋如何处理类型的一个误解,可以通过阅读规范的相关部分来解决:

Http://golang.org/ref/spec#type_identity

The relevant distinction that I was unaware of was that of 名字 and 无名氏 types.

名为 的类型是具有名称的类型,例如 int、 int64、 float、 string、 bool。此外,使用“ type”创建的任何类型都是命名类型。

未命名的 类型包括[] string、 map [ string ] string、[4] int。它们没有名称,只是对应于如何构造它们的描述。

如果比较两个命名类型,则名称必须匹配,以便它们可以互换。如果比较命名类型和未命名类型,那么 只要基底形式匹配就可以了!

e.g. given the following types:

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)

我有点内疚,我不知道这么快,所以我希望澄清类型云雀一点为别人!这意味着比我最初想象的要少得多的角色:)

问题和答案都很有启发性。然而,我想提出一个在 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
}

如果基础类型是基元类型,则 GO 不允许将一种类型的变量直接赋值给另一种类型,反之亦然。但是,可以将该值强制转换为目标类型并使用。

package main
import (
"fmt"
)


type T int


type U T


type V U


type UU U


func main() {


var s int
var t T
var u U
var uu UU


s = 9
t = 10
u = 11
uu = 111


fmt.Println(s)
fmt.Println(t)
fmt.Println(u)
fmt.Println(uu)


fmt.Println("========")


//s = t
//u = s
//v = s


u = (U)(uu)


//fmt.Println(s)
//fmt.Println(u)
fmt.Println(u)


}

Like the other people said anInt := 0 chooses a type for 0 rather than just a number. The only way I know to keep it without a type is to use const. If you use const instead of := then this can work.

func main() {
const anInt = 0
test(anInt)
}