Go从入门到精通——类型别名(Type Alias)

类型别名(Type Alias)

  类型别名是 Go 1.9 版本添加的新功能。主要用于代码升级、迁移中类型的兼容性问题。

  在 C/C++ 语言中,代码重构升级可以使用宏快速定义新的一段代码。Go 语言中没有选择加入宏,而是将解决重构中最麻烦的类型名变更问题。

 1.1、区分类型别名与类型定义

  类型别名的写法:

1
type TypeAlias = Type

  类型别名规定:TypeAlias 只是 Type 的别名,本质上 TypeAlias 与 Type 是同一个类型。

  类型别名与类型定义表面上看只有一个等号的差异,那么它们的实际区别呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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、非本地类型不能定义方法

  能够随意地为各种类型起名字,是否意味着可以在自己包里为这些类型任意添加方法?答案:不能。

  举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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、在结构体成员嵌入时使用别名

  当类型别名作为结构体嵌入的成员时会发生什么情况?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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 类型。

posted @   左扬  阅读(1089)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
levels of contents
点击右上角即可分享
微信分享提示