• 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 类型。

  • 相关阅读:
    微信扫码支付模式一和模式二的区别
    spring boot MongoDB的集成和使用
    Java 8 中的 Streams API 详解
    大并发量的订单的解析
    Springboot项目打成war包,部署到tomcat上,正常启动访问报错404
    最详细的虚拟机安装centos7教程
    nginx限制上传大小和超时时间设置说明/php限制上传大小
    一级域名和二级域名的区别是什么?分别有什么作用?
    快递物流查询接口介绍
    java 使用volatile实现线程数据的共享
  • 原文地址:https://www.cnblogs.com/zuoyang/p/15875873.html
Copyright © 2020-2023  润新知