在 Go 中,下面两种写法看起来相似,但含义完全不同:
type UserID int
type Score = int
type UserID int:定义一个全新的类型type Score = int:为int创建一个类型别名
一、使用 type T U 定义新类型
type UserID int
这会创建一个名为 UserID 的新类型。虽然它的底层类型是 int,但 UserID 与 int 并不是同一种类型。
var id UserID = 100
var number int = 200
number = id // 编译错误
number = int(id) // 正确,需要显式转换
新类型之间也不能随意混用:
type UserID int
type OrderID int
func findUser(id UserID) {}
func findOrder(id OrderID) {}
var userID UserID
var orderID OrderID
findUser(userID) // 正确
findUser(orderID) // 编译错误
即使 UserID 和 OrderID 的底层类型都是 int,Go 也会把它们视为两个不同的类型。
二、使用 type T = U 定义类型别名
type Score = int
这不会创建新类型,Score 只是 int 的另一个名字。
var score Score = 100
var number int = 200
number = score // 正确
score = number // 正确
类型别名常用于给复杂类型提供更短的名字、保持旧代码兼容,或在包迁移时保留原有类型身份:
type StringList = []string
这里的 StringList 仍然就是 []string,不会产生一个新的类型。
三、新类型可以定义方法
使用新类型时,可以为它定义专属方法:
type UserID int
func (id UserID) Valid() bool {
return id > 0
}
但类型别名不会创建独立类型,因此不能借此为 int 增加方法:
type Score = int
// 编译错误:Score 只是 int 的别名
func (s Score) Valid() bool {
return s >= 0
}
四、两种写法的对比
| 对比项 | type UserID int | type Score = int |
|---|---|---|
| 是否创建新类型 | 是 | 否 |
| 是否与原类型完全相同 | 否 | 是 |
| 是否可以直接赋值 | 通常不可以 | 可以 |
| 是否需要显式转换 | 通常需要 | 不需要 |
| 是否可以定义方法 | 可以 | 不能创建独立方法 |
| 主要用途 | 表达业务语义、限制误用 | 重命名、兼容、简化类型 |
五、实际开发中如何选择?
如果类型代表不同的业务概念,建议使用新类型:
type UserID int64
type ProductID int64
type Price int64
这样可以避免把用户 ID、商品 ID 和价格混在一起。
如果只是想给已有类型换一个名字,并且希望它与原类型完全兼容,可以使用类型别名:
type HeaderMap = map[string]string
简单来说:
type UserID int // 创建新类型
type UserID = int // 创建类型别名
需要“区分身份”时使用新类型,需要“换个名字”时使用类型别名。