typedesc[T]

在许多情况下,Nim允许您将类型的名称视为常规值。 这些值仅在编译阶段存在,但由于所有值必须具有类型,因此 typedesc 被视为其特殊类型。

typedesc 就像一个通用类型。例如,符号 int 的类型是 typedesc [int] 。 就像常规泛型类型一样,当泛型参数被省略时,typedesc表示所有类型的类型类。 作为一种语法方便,您还可以使用typedesc作为修饰符。

具有 typedesc 参数的过程被认为是隐式通用的。 它们将针对提供的类型的每个唯一组合进行实例化,并且在proc的主体内,每个参数的名称将引用绑定的具体类型:

  1. proc new(T: typedesc): ref T =
  2. echo "allocating ", T.name
  3. new(result)
  4.  
  5. var n = Node.new
  6. var tree = new(BinaryTree[int])

当存在多种类型的参数时,它们将自由地绑定到不同类型。 要强制绑定一次行为,可以使用显式通用参数:

  1. proc acceptOnlyTypePairs[T, U](A, B: typedesc[T]; C, D: typedesc[U])

绑定后,类型参数可以出现在proc签名的其余部分中:

  1. template declareVariableWithType(T: typedesc, value: T) =
  2. var x: T = value
  3.  
  4. declareVariableWithType int, 42

通过约束与类型参数匹配的类型集,可以进一步影响重载解析。 这在实践中通过模板将属性附加到类型。 约束可以是具体类型或类型类。

  1. template maxval(T: typedesc[int]): int = high(int)
  2. template maxval(T: typedesc[float]): float = Inf
  3.  
  4. var i = int.maxval
  5. var f = float.maxval
  6. when false:
  7. var s = string.maxval # 错误,没有为字符串实现maxval
  8.  
  9. template isNumber(t: typedesc[object]): string = "Don't think so."
  10. template isNumber(t: typedesc[SomeInteger]): string = "Yes!"
  11. template isNumber(t: typedesc[SomeFloat]): string = "Maybe, could be NaN."
  12.  
  13. echo "is int a number? ", isNumber(int)
  14. echo "is float a number? ", isNumber(float)
  15. echo "is RootObj a number? ", isNumber(RootObj)

传递 typedesc 几乎完全相同,只是因为宏没有一般地实例化。 类型表达式简单地作为 NimNode 传递给宏,就像其他所有东西一样。

  1. import macros
  2.  
  3. macro forwardType(arg: typedesc): typedesc =
  4. # ``arg`` 是 ``NimNode`` 类型
  5. let tmp: NimNode = arg
  6. result = tmp
  7.  
  8. var tmp: forwardType(int)