Go 基本概念速记速查之反射、泛型
date
Jun 26, 2023
slug
golang-start-reflect-generic
status
Published
tags
Go
summary
Go 基本概念汇总速记
type
Post
反射
变量和反射对象转换
var → reflect.ValueOf → interface{} → reflect.Value
reflect.Value → .Interface() → 断言 → var
reflect.ValueOf reflect.TypeOf 参数都是 interface{} 所以默认会把入参视为接口处理。
reflect.Value.Interface() 返回变量的接口包装类型,再通过对接口包装做断言还原回原始变量。
通过反射修改原值
想要通过反射修改原本变量的值时,可以通过 Setxx方法,不过前提是 reflect.Value 必须是可以寻址的,而 reflect.Value.Elem() 提供了这个入口,Elem 返回 value 接口内部的值或者 value 指针指向的值,所以要想修改原值,第一点需要传递指针进来,第二点通过 reflect.Value.Elem().SetX 赋值
过程类似下面,i 直接赋值的话,相当于重新指定了新值,而不是在原位修改,要想在原位修改,需要通过 v:= &i 获取指针,然后通过指针间接修改 i 的值。
泛型
泛型函数 generic function
在没有泛型的时候,想要处理整型和浮点型字典的求和需要写两遍
Go 1.18 引入了泛型,定义一个泛型函数,在函数名后面增加了 [] 类型形参列表 type parameter list,其中定义类型形参 type parameter K 和 V,K 的类型约束 type constraint 必须是实现 comparable 接口的,因为 map 的 key 要求必须能够用 == 或 != 比较,另外要求 V 要么是 int64 要么是 float64。
使用的时候传入类型实参,K 传入 string,V 传入 int64 或 float64,这个传入过程就是泛型的实例化 instantiation
为了简化代码,Go 的泛型支持类型推断,调用时可以不用传形参
输出结果
将类型约束放在一个接口中,进一步规范代码
接口 interface 含义的变化
上面代码中
看着有点奇怪,这是 1.18 新增的语法,而且 interface 含义也变了。
在之前 interface 的含义是方法的集合,而现在的含义变为了类型的集合。
以前是只要实现了接口中的方法,就算是实现了接口,现在则进一步要求结构体的底层数据结构要符合接口的类型。
例如 Int 接口表示所有 int 类型的集合,也就是 Int 可以代表所有的 int 类型,同理 Uint 可以代表所有 uint 类型。
泛型结构体和方法 generic receiver
没有泛型时定义队列时,需要针对每种类型都写一遍相同的处理代码,而现在用泛型定义一个 Queue 就可以了。
在定义 Queue 结构体时,增加一个类型形参 T,约束是 any 类型,也就是 interface{},在 Go 1.18 中 any 就是 interface{} 的别名,之后给 Queue 添加方法,注意 Queue[T] 加一起是类型。
使用时传入类型实参 int 和 string,就可以处理不同类型的队列了。
输出
参考: