[

](erik-engheim.medium.com/?source=pos…)
6月17日
-
3分钟阅读
[
拯救
面向非初学者的Golang泛型技术
在Go中快速掌握泛型

我不打算在这个故事中教你泛型,而是假设你已经了解泛型、参数化类型或基于模板的编程。
这里展示的是Go泛型的基本知识。类型参数受到接口的约束。这意味着你可以要求你的类型参数T ,实现某些方法或属于某些类型。在这里,我们指定接口Number 匹配任何属于int 、int64 或float64 的东西。
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中尝试这个例子。
通用类型
值得注意的是,在定义参数化类型时,我们添加的方法不能引入新的类型参数。它们只能使用类型定义中定义的参数。因此,你会注意到对于Push 和Pop ,我们没有指定对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~ ,那么Newton 和Kg 就不会被认为是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的其他文章。
- 给Go程序员的1.18版刷新- 澄清自Go获得模块以来Go的变化,以及涵盖你在远离Go编程时经常忘记的东西。
- Go是一种系统编程语言吗?-有了自动内存管理,Go真的可以成为一种系统编程语言吗?是的,这篇文章解释了原因。
- Go不需要Java风格的GC- Go的垃圾收集方法与Java和C#非常不同。下面我们来看看为什么Go可以使用比Java更简单的垃圾收集器。
- Go比Java更面向对象
- 用Go保持简单- 我在奥斯陆的NDC会议上的演讲录音。