集合类型

集合类型是数学概念集合的模型。集合的基础类型只能是具有一定大小的序数类型,即:

  • int8-int16
  • uint8/byte-uint16
  • char
  • enum
  • 序数子区间类型,即 range[-10..10] 或等效类型。

当使用带符号的整数文字构造集合时,该集合的基础类型被定义为区间 0 .. DefaultSetElements-1 ,其中 DefaultSetElements 目前始终为 2^8。 集合基础类型的最大区间长度为 MaxSetElements ,目前始终为 2^16。具有更大区间长度的类型将被强制转换为区间 0 .. MaxSetElements-1 。

原因是集合被实现为高性能的bit vector。 试图用太大类型来声明集合将导致一个错误:

  1. var s: set[int64] # 错误:集合太大;对于具有超过 2^16 个元素的序数类型,请使用 `std/sets`

注意: Nim 还提供了 hash sets (你需要通过 import std/sets 导入它们),它们没有这样的限制。

集合可以通过集合构造器来构造: {} 是空集。空集的类型与任何具体的集合类型兼容。 构造器也可以用来包含元素(和元素范围)。

  1. type
  2. CharSet = set[char]
  3. var
  4. x: CharSet
  5. x = {'a'..'z', '0'..'9'} # 这构建了一个包含从'a' 到 'z' 的字母和从 '0' 到 '9' 的数字的集合。

`std/setutils` 模块提供了一种从可迭代对象初始化集合的方法:

  1. import std/setutils
  2. let uniqueChars = myString.toSet

集合支持以下操作。

运算含义
A + B两个集合的并集
A * B两个集合的交集
A - B两个集合的差集(A不包含B的元素)
A == B集合相等
A <= B子集关系(A是B的子集或等于B)
A < B严格子集关系(A是B的真子集)
e in A集合成员关系(A包含元素e)
e notin AA不包含元素e
contains(A, e)A包含元素e
card(A)A的基数(A中元素的数量)
incl(A, elem)相同于 A = A + {elem}
excl(A, elem)相同于 A = A - {elem}

位域

集合经常被用来为过程的 标记 定义类型。 这是比定义整数常量更利落的解决方案(而且类型安全),因为整数常量必须被 or “或”在一起。

enum、set和cast可以像下面这样一起使用:

  1. type
  2. MyFlag* {.size: sizeof(cint).} = enum
  3. A
  4. B
  5. C
  6. D
  7. MyFlags = set[MyFlag]
  8. proc toNum(f: MyFlags): int = cast[cint](f)
  9. proc toFlags(v: int): MyFlags = cast[MyFlags](v)
  10. assert toNum({}) == 0
  11. assert toNum({A}) == 1
  12. assert toNum({D}) == 8
  13. assert toNum({A, C}) == 5
  14. assert toFlags(0) == {}
  15. assert toFlags(7) == {A, B, C}

要注意set是怎样将枚举值转换为2的幂值。

如果在C中使用枚举和集合,请使用distinct cint。

关于与 C 语言的互操作性,参阅bitsize 编译指示