Go 1.9 新特性 Type Alias 详解(2)

定义了一个接口I,从代码上看,只有MyUser2实现了它,但是我们代码的演示中,发现User也实现了接口I,所以这就验证了我们的推到是正确的,返回来如果User实现了某个接口,那么它的type alias也同样会实现这个接口。

以上讲了很多示例都是类型struct的别名,我们看下接口interface的type alias是否也是等价的。

type I interface { m() } type MyI1 I type MyI2 = I type MyInt int func (i MyInt) m(){ fmt.Println("MyInt.m") }

定义了一个接口I,MyI1是基于I的新类型;MyI2是I的类型别名;MyInt实现了接口I。下面进行测试。

//Blog: //Wechat:flysnow_org func main() { //赋值实现类型MyInt var i I = MyInt(0) var i1 MyI1 = MyInt(0) var i2 MyI2 = MyInt(0) //接口间相互赋值 i = i1 i = i2 i1 = i2 i1 = i i2 = i i2 = i1 }

以上代码运行是正常的,这个是前面讲的具体类型(struct,int等)的type alias不一样,只要实现了接口,就可以相互赋值,管你是新定义的接口MyI1,还是接口的别名MyI2。

类型的嵌套

我们都知道type alias的两个类型是等价的,但是他们在类型嵌套时有些不一样。

//Blog: //Wechat:flysnow_org func main() { my:=MyStruct{} my.T2.m1() } type T1 struct { } func (t T1) m1(){ fmt.Println("T1.m1") } type T2 = T1 type MyStruct struct { T2 }

示例中T2是T1的别名,但是我们把T2嵌套在MyStruct中,在调用的时候只能通过T2这个名称调用,而不能通过T1,会提示没这个字段的。反过来也一样。

这是因为T1,T2是两个名称,虽然他们等价,但他们是具有两个不同名字的等价类型,所以在类型嵌套的时候,就是两个字段。

当然我们可以把T1,T2同时嵌入到MyStrut中,进行分别调用。

//Blog: //Wechat:flysnow_org func main() { my:=MyStruct{} my.T2.m1() my.T1.m1() } type MyStruct struct { T2 T1 }

以上也是可以正常运行的,证明这是具有两个不同名字的,同种类型的字段。

下面我们做个有趣的实验,把main方法的代码改为如下:

//Blog: //Wechat:flysnow_org func main() { my:=MyStruct{} my.m1() }

猜猜是不是可以正常编译运行呢?答应可能出乎意料,是不能正常编译的,提示如下:

./main.go:25:4: ambiguous selector my.m1

其实想想很简单,不知道该调用哪个,太模糊了,匹配不了,不然该用T1的m1,还是T2的m1。这种结果不限于方法,字段也也一样;也不限于type alias,type defintion也是一样的,只要有重复的方法、字段,就会有这种提示,因为不知道该选择哪个。

类型循环

type alias的声明,一定要留意类型循环,不要产生了循环,一旦产生,就会编译不通过,那么什么是类型循环呢。假如type T2 = T1,那么T1绝对不能直接、或者间接的引用到T2,一旦有,就会类型循环。

type T2 = *T2 type T2 = MyStruct type MyStruct struct { T1 T2 }

以上两种定义都是类型循环,我们自己在使用的过程中,要避免这种定义的出现。

byte and rune

这两个类型一个是int8的别名,一个是int32的别名,在Go 1.9之前,他们是这么定义的。

type byte byte type rune rune

现在Go 1.9有了type alias这个新特性后,他们的定义就变成如下了:

type byte = uint8 type rune = int32

恩,非常很省事和简洁。

导出未导出的类型

type alias还有一个功能,可以导出一个未被导出的类型。

package lib //Blog: //Wechat:flysnow_org type user struct { name string Email string } func (u user) getName() string { return u.name } func (u user) GetEmail() string { return u.Email } //把这个user导出为User type User = user

user本身是一个未导出的类型,不能被其他package访问,但是我们可以通过type User = user,定义一个User,这样这个User就可以被其他package访问了,可以使用user类型导出的字段和方法,示例中是Email字段和GetEmail方法,另外未被导出name字段和getName方法是不能被其他package使用的。

小结

type alias的定义,本质上是一样的类型,只是起了一个别名,源类型怎么用,别名类型也怎么用,保留源类型的所有方法、字段等。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d6619f0a939541c9139aa112ceef0d11.html