泛型

泛型是 Nim 通过 type parameters “类型参数” 把过程、迭代器或类型参数化的方法。在不同的上下文里,用方括号引入类型参数,或者实例化泛型过程、迭代器及类型。

以下例子展示了如何构建一个泛型二叉树:

  1. type
  2. BinaryTree*[T] = ref object # 二叉树是具有
  3. # 泛型参数 `T` 的泛型类型。
  4. le, ri: BinaryTree[T] # 左右子树;可能是nil
  5. data: T # 存储在节点中的数据
  6. proc newNode*[T](data: T): BinaryTree[T] =
  7. # 节点的构造函数
  8. result = BinaryTree[T](le: nil, ri: nil, data: data)
  9. proc add*[T](root: var BinaryTree[T], n: BinaryTree[T]) =
  10. # 向树中插入一个节点
  11. if root == nil:
  12. root = n
  13. else:
  14. var it = root
  15. while it != nil:
  16. # 使用泛型的 `cmp` 过程,比较数据项;
  17. # 这适用于任意具有 `==` 和 `<` 运算符的类型
  18. var c = cmp(it.data, n.data)
  19. if c < 0:
  20. if it.le == nil:
  21. it.le = n
  22. return
  23. it = it.le
  24. else:
  25. if it.ri == nil:
  26. it.ri = n
  27. return
  28. it = it.ri
  29. proc add*[T](root: var BinaryTree[T], data: T) =
  30. # 便捷过程:
  31. add(root, newNode(data))
  32. iterator preorder*[T](root: BinaryTree[T]): T =
  33. # 二叉树预遍历。
  34. # 使用显式堆栈。
  35. # (这比递归迭代器工厂更有效).
  36. var stack: seq[BinaryTree[T]] = @[root]
  37. while stack.len > 0:
  38. var n = stack.pop()
  39. while n != nil:
  40. yield n.data
  41. add(stack, n.ri) # 将右子树push到堆栈上
  42. n = n.le # 并跟踪左子树
  43. var
  44. root: BinaryTree[string] # 用 `string` 实例化二叉树
  45. add(root, newNode("hello")) # 实例化 `newNode` 和 `add`
  46. add(root, "world") # 实例化 `add` 过程
  47. for str in preorder(root):
  48. stdout.writeLine(str)

这里的 T 称为 generic type parameter “泛型类型参数”,或者 type variable “类型变量”。