说明
type关键字又称之为类型别名,类型别名这个概念是Go1.9版本新添加的功能,主要用于解决代码升级、迁移中存在的类型兼容问题。
在go1.9版本之前定义内建类型的代码是这样的:
type byte uint8
type rune int32
而在go1.9版本之后变为:
type byte = uint8
type rune = int32
这个修改就是配合类型别名而进行的修改。
类型别名和类型定义的区别
定义类型别名的写法如下:
type TypeAlias = Type
在go中类型别名规定:TypeAlias是Type类型的别名。本质来说TypeAlias和Type是属于同一个类型。就如同一个孩子有大名和乳名。无论是乳名还是大名都表示这个孩子。
类型别名和类型定义从表面上看只是一个等号的不同,那么它们的区别是什么呢?
下面我们通过一段代码来查看一下二者的区别:
package main
import "fmt"
type NewInt int // 将NewInt定义为int类型
type IntAlias = int // 将int取一个别名IntAlias
func main() {
// 将a声明为NewInt类型
var a NewInt
// 查看a的类型名
fmt.Printf("a type: %T
", a) // a type: main.NewInt
// 将a2声明为IntAlias类型
var a2 IntAlias
// 查看a2的类型名
fmt.Printf("a2 type: %T
", a2) // a2 type: int
}
上面代码结果显示 a 的类型是 main.NewInt,表示 main 包下定义的 NewInt 类型,a2 类型是 int,IntAlias 类型只会在代码中存在,编译完成时,不会有 IntAlias 类型。
非本地类型不能定义方法
能够随意地为各种类型起名字,是否意味着可以在自己包里为这些类型任意添加方法呢?参见下面的代码演示:
package main
import (
"time"
)
// 定义time.Duration的别名为MyDuration
type MyDuration = time.Duration
// 为MyDuration添加一个函数
func (m MyDuration) EasySet(a string) {
}
func main() {
}
在上面的代码中给time.Duration设置一个类型别名叫做MyDuration。并且在后续的代码中为这个别名添加了一个方法。
此时编译代码,就会出现下面的报错信息:
cannot define new methods on non-local type time.Duration
编译器提示:不能在一个非本地的类型 time.Duration 上定义新方法,非本地类型指的就是 time.Duration 不是在 main 包中定义的,而是在 time 包中定义的,与 main 包不在同一个包中,因此不能为不在一个包中的类型定义方法。
解决这个问题有下面两种方法:
- 将第 8 行修改为 type MyDuration time.Duration,也就是将 MyDuration 从别名改为类型;
- 将 MyDuration 的别名定义放在 time 包中。