type MyInt int 创建新类型,可定义方法、需显式转换;type MyInt = int 是别名,与原类型完全等价、无法单独定义方法。
和
看似只差一个等号,但语义完全不同:前者创建新类型,后者只是给已有类型起个别名。
type MyInt int 创建独立命名类型
这是类型定义(type definition),go 会为
分配一个全新的类型身份,和
不兼容:
可以在包外定义方法(比如
)
不能直接赋值给
,也不能作为接收
参数的函数入参 —— 编译报错:
必须显式转换:
或
才能互转
在反射或
输出中显示为
,不是
type MyInt = int 是完全等价的类型别名
这是类型别名(type alias),Go 1.9+ 引入,
在编译期被彻底擦除,和
完全同一类型:
无法为
单独定义方法(因为本质上就是
,而你不能在
所在包外给它加方法)
可直接赋值、传参、比较:
、
都合法
返回空字符串,
输出是
常见于标准库:如
、
为什么 MyInt(int) 转换不报错,但 MyInt(0) 有时会意外失败
显式转换本身合法,但容易踩两个坑:
如果
是基于
定义的,
没问题;但若底层类型是
或带符号差异的类型,常量推导可能出错
函数参数接收
,但你传了未转换的
字面量(如
),会报错 —— Go 不做隐式转换,哪怕值安全
结构体字段是
,用字面量初始化时需保持类型一致:
,不能写
什么时候该用哪个
选
当你需要:
领域建模(如
、
)
附加方法(验证、格式化、单位转换等)
防止误用(比如把普通
当作端口号传进网络函数)
选
当你只是想换个名字提升可读性,且不需要任何类型隔离或方法扩展 —— 实际项目中这种需求极少,多数场景应优先用类型定义。
真正容易被忽略的是:类型别名在跨包方法绑定和接口实现上完全不可用,而命名类型的方法集是独立携带的。一旦你打算封装行为,
就不再是捷径,而是限制。
type MyInt inttype MyInt = intmyintintMyIntfunc (m MyInt) Double() MyIntintintcannot use x (type MyInt) as type intint(x)MyInt(i)%Tmain.MyIntintMyIntintMyIntintintvar i MyInt = 42fmt.Println(i)reflect.TypeOf(i).Name()%Tinttype byte = uint8type rune = int32MyIntintMyInt(0)int64MyIntintfoo(42)MyIntstruct{ Port MyInt }{Port: MyInt(8080)}{8080}type MyInt inttype UserID inttype PortNumber uint16inttype MyInt = int=