元组和对象类型

元组或对象类型的变量是异构存储容器。元组或对象定义了一个类型的各类 字段 。元组还定义了字段的 顺序 。 元组是有很少抽象可能性的异构存储类型。 () 可用于构造元组。构造函数中字段的顺序必须与元组定义的顺序相匹配。 如果它们以相同的顺序指定相同类型的相同字段,则不同的元组类型 等效 。字段的 名称 也必须相同。

  1. type
  2. Person = tuple[name: string, age: int] # 表示人的类型:
  3. # 由名字和年龄组成。
  4. var person: Person
  5. person = (name: "Peter", age: 30)
  6. assert person.name == "Peter"
  7. # 一样,但可读性不太好
  8. person = ("Peter", 30)
  9. assert person[0] == "Peter"
  10. assert Person is (string, int)
  11. assert (string, int) is Person
  12. assert Person isnot tuple[other: string, age: int] # `other` 是不同的标识符

可以使用括号和尾随逗号,构造具有一个未命名字段的元组:

  1. proc echoUnaryTuple(a: (int,)) =
  2. echo a[0]
  3. echoUnaryTuple (1,)

事实上,每个元组结构都允许使用尾随逗号。

字段将会对齐,以此获得最佳性能。对齐与 C 编译器的方式兼容。

为了与 object 声明保持一致, type 部分中的元组也可以用缩进而不是 [] 来定义:

  1. type
  2. Person = tuple # 代表人的类型
  3. name: string # 人的名字
  4. age: Natural # 以及年龄

对象提供了许多元组没有的特性。对象提供继承和隐藏其他模块字段的能力。启用继承的对象在运行时具有相关类型的信息,可以使用 of 运算符来确定对象的类型。 of 运算符类似于 Java 中的 instanceof 运算符。

  1. type
  2. Person = object of RootObj
  3. name*: string # *表示可以从其他模块访问 `name`
  4. age: int # 没有 * 表示该字段已隐藏
  5. Student = ref object of Person # 学生是人
  6. id: int # 有个 id 字段
  7. var
  8. student: Student
  9. person: Person
  10. assert(student of Student) # 是真
  11. assert(student of Person) # 也是真

对模块外部可见的对象字段必须用 * 标记。与元组相反,不同的对象类型永远不会 等价 。没有祖先的对象是隐式的 final ,因此没有隐藏的类型字段。 可以使用 inheritable 编译指示来引入除 system.RootObj 之外的新根对象。

  1. type
  2. Person = object # final 对象的例子
  3. name* : string
  4. age: int
  5. Student = ref object of Person # 错误: 继承只能用于非 final 对象
  6. id: int

对于元组和对象的赋值操作,将拷贝每个组件。 重写这种拷贝行为的方法描述在这里