面向非初学者的Golang泛型技术

50 阅读2分钟

[

Erik Engheim

](erik-engheim.medium.com/?source=pos…)

Erik Engheim

关注

6月17日

-

3分钟阅读

[

拯救

](medium.com/m/signin?ac…)

面向非初学者的Golang泛型技术

在Go中快速掌握泛型

我不打算在这个故事中教你泛型,而是假设你已经了解泛型、参数化类型或基于模板的编程。

这里展示的是Go泛型的基本知识。类型参数受到接口的约束。这意味着你可以要求你的类型参数T ,实现某些方法或属于某些类型。在这里,我们指定接口Number 匹配任何属于intint64float64 的东西。

type Number interface {    int | int64 | float64}func Sum[T Number](numbers []T) T {    var total T    for _, x := range numbers {        total += x    }    return total}

你可以在Go Playground中尝试这个例子。

通用类型

值得注意的是,在定义参数化类型时,我们添加的方法不能引入新的类型参数。它们只能使用类型定义中定义的参数。因此,你会注意到对于PushPop ,我们没有指定对T的约束。事实上,在方法定义中没有任何提示T 是一个类型参数。相反,Go从类型定义中获得了这种知识。这是一个值得注意的限制条件。

type Stack[T any] struct {	items []T}func (stack *Stack[T]) Push(value T) {	stack.items = append(stack.items, value)}func (stack *Stack[T]) Pop() {	n := len(stack.items)	if n <= 0 {		panic("Cannot pop an empty stack!")	}	stack.items = stack.items[:n-1]}

预包装的约束条件

在我们的第一个例子中,我们定义了我们自己的Number 接口,但你不需要这样做。golang.org/x/exp/const…包给出了大量最有用的约束条件的集合。下面是约束包中定义的一些接口。

type Signed interface {	~int | ~int8 | ~int16 | ~int32 | ~int64}type Unsigned interface {	~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr}type Integer interface {	Signed | Unsigned}type Float interface {	~float32 | ~float64}type Ordered interface {	Integer | Float | ~string}

注意到tilde~ 的用法。这是因为Go可以让你轻松地定义新的类型,这些类型是由原始类型派生的。例如,在编写模拟火箭发射物理学的代码时,我是这样定义公斤和牛顿(力)的类型的。

type Newton float64type Kg float64

如果你没有对Float 使用tilde~ ,那么NewtonKg 就不会被认为是Float 的值,这将是不实际的。

我在定义二进制搜索树的节点时使用了这个包的约束。

import (	"fmt"	"golang.org/x/exp/constraints")// A node in a binary tree which you can search by keytype TreeNode[K constraints.Ordered, V any] struct {	Key         K	Value       V	left, right *TreeNode[K, V]}// Give string representation of node in print statementsfunc (n *TreeNode[K, V]) String() string {	return fmt.Sprintf("TreeNode(%v, %v)", n.Key, n.Value)}// Insert node n into a leaf underneath parent node.// Position will be determined based on value of keyfunc (parent *TreeNode[K, V]) Insert(n *TreeNode[K, V]) {	if n.Key >= parent.Key {		if parent.right == nil {			parent.right = n		} else {			parent.right.Insert(n)		}	} else {		if parent.left == nil {			parent.left = n		} else {			parent.left.Insert(n)		}	}}

其他与Golang有关的故事

如果你有兴趣阅读更多关于Go的内容,我还写了一些关于Go的其他文章。