Go从入门到精通——类型别名(Type Alias)
类型别名(Type Alias)
类型别名是 Go 1.9 版本添加的新功能。主要用于代码升级、迁移中类型的兼容性问题。
在 C/C++ 语言中,代码重构升级可以使用宏快速定义新的一段代码。Go 语言中没有选择加入宏,而是将解决重构中最麻烦的类型名变更问题。
1.1、区分类型别名与类型定义
类型别名的写法:
type TypeAlias = Type
类型别名规定:TypeAlias 只是 Type 的别名,本质上 TypeAlias 与 Type 是同一个类型。
类型别名与类型定义表面上看只有一个等号的差异,那么它们的实际区别呢?
package main import "fmt" // 将 NewInt 定义为 int 类型 type NewInt int // 将 int 取一个别名叫 IntAlias type IntAlias = int func main() { // 将 a 声明 NewInt 类型 var a NewInt // 查看 a 的类型名 fmt.Printf("a type: %T\n", a) // 将 a2 声明为 IntAlias 类型 var a2 IntAlias // 查看 a2 的类型名 fmt.Printf("a2 type: %T\n", a2) }
代码说明如下:
a 的类型是 main.NewInt,表示 main 包下定义的 NewInt 类型。
a2 类型是 int。
IntAlias 类型只会在代码中存在,编译完成时,不会有 IntAlias 类型。
1.2、非本地类型不能定义方法
能够随意地为各种类型起名字,是否意味着可以在自己包里为这些类型任意添加方法?答案:不能。
举个例子:
package main import ( "fmt" "time" ) // 定义 time.Duration 的别名为 MyDuration type MyDuration = time.Duration // 为 MyDuration 添加一个方法 func (m MyDuration) EasySet(a string){ } func main() { }
代码输出如下:
编译器提示:
不能在一个非本地的类型 time.Duration 上定义新方法。非本地方法指的就是 time.Duration 的代码所在的包,也就是 main 包。
因为 time.Duration 是在 time 包中定义的,在 main 包中使用。time.Duration 包与 main 包不在同一个包,因此不能为不在一个包中的类型定义方法。
解决办法:
- 将 "type MyDuration = time.Duration" 修改为 "type MyDuration time.Duration",从别名改为类型。
- 将 MyDuration 的别名定义放在 time 包中。
1.3、在结构体成员嵌入时使用别名
当类型别名作为结构体嵌入的成员时会发生什么情况?
package main import ( "fmt" "reflect" ) //定义商标结构 type Brand struct { } //为商标结构添加 Show() 方法 func (t Brand) Show() { } // 为 Brand 定义一个别名 FakeBrand type FakeBrand = Brand // 定义车辆结构 type Vehicle struct { //嵌入两个结构 FakeBrand Brand } func main() { // 声明变量 a 为车辆类型 var a Vehicle // 指定调用 FakeBrand 的 Show a.FakeBrand.Show() // 取 a 的类型反射对象 ta := reflect.TypeOf(a) // 遍历 a 的所有成员 for i := 0; i < ta.NumField(); i++ { // a 的成员信息 f := ta.Field(i) // 打印成员的字段名和类型 fmt.Printf("FieldName: %v, FieldType: %v\n", f.Name, f.Type.Name()) } }
代码输出如下:
这个例子中,FakeBrand 是 Brand 的一个别名。在 Vehicle 中嵌入 FakeBrand 和 Brand 并不意味着嵌入两个 Brand。FakeBrand 的类型会以名字的方式保留在 Vehicle 的成员中。
注意 FakeBrand 本质是 Brand 类型。