类型类

类型类是特殊的伪类型,可在重载解析或使用 is 运算符时针对性地匹配某些类型。Nim 支持以下内置类型类:

类型匹配
object任意 object 类型
tuple任意 tuple 类型
enum任意 enumeration
proc任意 proc 类型
iterator任意 iterator 类型
ref任意 ref 类型
ptr任意 ptr 类型
var任意 var 类型
distinct任意 distinct 类型
array任意 array 类型
set任意 set 类型
seq任意 seq 类型
auto任意 类型

此外,任何泛型类型都会自动创建一个同名的类型类,可匹配该泛型类的任意实例。

类型类通过标准的布尔运算符可组合成更复杂的类型类。

  1. # 创建一个类型类,可以匹配所有元组和对象类型
  2. type RecordType = (tuple or object)
  3. proc printFields[T: RecordType](rec: T) =
  4. for key, value in fieldPairs(rec):
  5. echo key, " = ", value

泛型参数列表中的参数类型约束可以通过 , 进行分组,并以 ; 结束,就像宏和模板中的参数列表那样:

  1. proc fn1[T; U, V: SomeFloat]() = discard # T 没有类型约束
  2. template fn2(t; u, v: SomeFloat) = discard # t 没有类型约束

虽然类型类在语法上接近于类 ML 语言中的代数数据类型 (ADT),但应该知道,类型类只是实例化时所必须遵守的静态约束。 类型类本身并非真的类型,只是一种检查系统,检查泛型是否最终被 解析 成某种单一类型。 与对象、变量和方法不同,类型类不允许运行时的类型动态特性。

例如,以下代码无法通过编译:

  1. type TypeClass = int | string
  2. var foo: TypeClass = 2 # foo 的类型在这里被解释为 int 类型
  3. foo = "this will fail" # 这里发生错误,因为 foo 是 int

Nim 允许将类型类和常规类型用作泛型类型参数的 type constraints “类型约束”:

  1. proc onlyIntOrString[T: int|string](x, y: T) = discard
  2. onlyIntOrString(450, 616) # 可以
  3. onlyIntOrString(5.0, 0.0) # 类型不匹配
  4. onlyIntOrString("xy", 50) # 不行,因为同一个 T 不能同时是两种不同的类型

proc 和 iterator 类型类也接受一个调用约定指示,以限制匹配的 proc 或 iterator 类型的调用约定。

  1. proc onlyClosure[T: proc {.closure.}](x: T) = discard
  2. onlyClosure(proc() = echo "hello") # valid
  3. proc foo() {.nimcall.} = discard
  4. onlyClosure(foo) # type mismatch