0x00
这次golang正式更新了泛型(之前的1.17 和1.18 Beta 1 中的只是测试版,其中有一些用法和正式版有较大的差别),是一次重大的更新,原以为在GO2.0的时候更新。
0x01 类型形参(Type Parameters)
在之前想要实现一些通用的功能还是比较麻烦的,而且代码冗余。
比如实现gorm添加json类型字段:
type Table struct {
AField A
BField B
}
type A struct {
AText string
}
func (A) GormDataType() string {
return "json"
}
func (a *A) Scan(value interface{}) error {
return json.Unmarshal(value.([]byte), a)
}
func (a A) Value() (value driver.Value, err error) {
src, err := json.Marshal(a)
return string(src), err
}
type B struct {
BText string
}
func (B) GormDataType() string {
return "json"
}
func (b *B) Scan(value interface{}) error {
return json.Unmarshal(value.([]byte), b)
}
func (b B) Value() (value driver.Value, err error) {
src, err := json.Marshal(b)
return string(src), err
}
可以看到A
和B
中的GormDataType
Scan
Value
方法几乎都是重复的,假如再添加C
D
那么就要添加6个重复发方法。
而golang 1.8开始正式支持泛型,那么利用泛型可以降低这样的代码冗余
使用泛型再次实现上述内容:
type Table struct {
AField JSON[A]
BField JSON[B]
}
type A struct {
AText string
}
type B struct {
BText string
}
type JSON[T any] struct {
Data T
}
func (JSON[T]) GormDataType() string {
return "json"
}
func (m *JSON[T]) Scan(value interface{}) error {
return json.Unmarshal(value.([]byte), &m.Data)
}
func (m JSON[T]) Value() (value driver.Value, err error) {
src, err := json.Marshal(m.Data)
return string(src), err
}
可以看到我这里定义了一个JSON[T any]
的类型专门处理json类型,此后添加C
D
字段就只需要定义相关的结构体并且添加JSON[C]
JSON[D]
即可。
其中any
类型也是这次更新后的新类型字段,但any
其实就是interface
类型的别称
源码:
// src/builtin/builtin.go 95行
// any is an alias for interface{} and is equivalent to interface{} in all ways.
type any = interface{}
个人感觉any
相比interface
在传参等场合更直观
比如:
func Println(v ...any){}
func Println(v ...interface){}
当然,在定义接口时还是得用interface
字段
判断类型
func (m *JSON[T]) Test() {
switch any(m.Data).(type) {
case A:
fmt.Println("A")
case B:
fmt.Println("B")
}
}
0x02 类型集合(Type Sets)
类型集合允许定义一个类型具有不同类型的集合
例如:
type Test interface {
int|float64
}
定义了一个Test
类型,表示为int
float64
类型的集合
如果不用泛型那怎么写呢
不使用泛型:
func Add(a, b interface{}) interface{} {
switch a.(type) {
case int:
return a.(int)+b.(int)
case float64:
return a.(float64)+b.(float64)
}
return 0
}
使用泛型:
func Add[T int | float64](a, b T) T {
return a + b
}
这样一对比使用泛型就简洁多了
应用:
type Num interface {
int | int64 | int32 |
float64 | float32 |
uint | uint8 | uint16 | uint64
}
func Add[T Num](a, b T) T {
return a + b
}
func Sub[T Num](a, b T) T {
return a - b
}
0x03 类型约束
type T interface {
int | float64 | ~string
}
其中的~string
表示定义的T
类型集合也支持底层类型是string
的类型
比如:
type A interface {
~string
}
func Splic[T A](a, b T) T {
return a + b
}
var BString string
func main() {
var a string = "a"
var b BString = "b"
Splic(a, b)
}
其中BString
是自定义的一个底层为string
的类型,如果没有加~
的话会报错
One comment
rehttNb