Go 泛型使用

Posted by 渐行渐远 on Sunday, March 20, 2022 共757字

泛型如何使用

函数 String 声明的参数列表中, str 类型被定义为泛型。支持泛型后,函数的签名中多出来 [T any] 部分,其中,any 表示泛型约束。在调用String函数时,也明确的指定了泛型类型为字符串。如果我们指定别的类型(和实际传入的类型不一致),编译会出错。

//例子1
func String[T any](str ...T) {
	fmt.Println(str)
}

func main() {
	String[string]("hello", "world!")
}

虽然 str 被声明为了泛型,但fmt.Println可以正常打印输出。在 Go 的内建类型了,也新增了anycomparable类型。

 94
 95
 96
 97
 98
 99
100
101
102
// any is an alias for interface{} and is equivalent to interface{} in all ways.
type any = interface{}

// comparable is an interface that is implemented by all comparable types
// (booleans, numbers, strings, pointers, channels, arrays of comparable types,
// structs whose fields are all comparable types).
// The comparable interface may only be used as a type parameter constraint,
// not as the type of a variable.
type comparable interface{ comparable }

函数max用于判断最大的入参,泛型约束指定为一个类型集合,实际类型是这三个类型中的任意一个。参考上面的例子,用any来替换这三种类型可以吗?不可以,因为编译器无法判断类型 T 能否进行比较。

//例子2
func max[T int64|float64|int32](a T, b T) T {
	if a > b {
		return a
	}
	return b
}

func main() {
	m := max[int64](1, 2)
	fmt.Print(m)
}

参考上述102行的comparable类型,泛型约束指定为comparable可以吗?不可以,comparable只能被用来比较是否相等,只有是 == 号的情况,才可以。我理解,它主要是用来给map使用的。

int64|float64|int32这种声明方式不够简洁,可以通过声明新的类型来简化,优化一下上面的例子2,重新声明了一个Number类型来表示这个泛型。

type Number interface {
	int64 | float64 | int32
}

func max[T Number](a T, b T) T {
	if a == b {
		return a
	}
	return b
}

例子3,我们在结构体上声明泛型,看起来可能比较吓人,但实际上并没有特别的新内涵,只是阐述将结构体中的字段声明为泛型的写法。

//例子3
type Live[K comparable, V any, V1 any] struct {
	Cache map[K]V
	Model V1
}

func (l *Live[K, V, V1]) Set(identity K, content V, model V1) {
	l.Cache[identity] = content
	l.Model = model
}

func (l *Live[K, V, V1]) Get(identity K) V {
	return l.Cache[identity]
}

type Key struct {Title string}
type Value struct {Title string}

func main() {
	live := &Live[Key, Value, string]{
		Cache: make(map[Key]Value),
	}
	live.Set(Key{Title: "key"}, Value{Title: "value"}, "")
	fmt.Println(live.Get(Key{Title: "key"}))
}