typedesc[T]
在许多情况下,Nim允许您将类型的名称视为常规值。 这些值仅在编译阶段存在,但由于所有值必须具有类型,因此 typedesc 被视为其特殊类型。
typedesc 就像一个通用类型。例如,符号 int 的类型是 typedesc [int] 。 就像常规泛型类型一样,当泛型参数被省略时, typedesc 表示所有类型的类型类。 作为一种语法方便,您还可以使用 typedesc 作为修饰符。
具有 typedesc 参数的过程被认为是隐式通用的。 它们将针对提供的类型的每个唯一组合进行实例化,并且在proc的主体内,每个参数的名称将引用绑定的具体类型:
- proc new(T: typedesc): ref T =
- echo "allocating ", T.name
- new(result)
- var n = Node.new
- var tree = new(BinaryTree[int])
当存在多种类型的参数时,它们将自由地绑定到不同类型。 要强制绑定一次行为,可以使用显式通用参数:
- proc acceptOnlyTypePairs[T, U](A, B: typedesc[T]; C, D: typedesc[U])
绑定后,类型参数可以出现在proc签名的其余部分中:
- template declareVariableWithType(T: typedesc, value: T) =
- var x: T = value
- declareVariableWithType int, 42
通过约束与类型参数匹配的类型集,可以进一步影响重载解析。 这在实践中通过模板将属性附加到类型。 约束可以是具体类型或类型类。
- template maxval(T: typedesc[int]): int = high(int)
- template maxval(T: typedesc[float]): float = Inf
- var i = int.maxval
- var f = float.maxval
- when false:
- var s = string.maxval # 错误,没有为字符串实现maxval
- template isNumber(t: typedesc[object]): string = "Don't think so."
- template isNumber(t: typedesc[SomeInteger]): string = "Yes!"
- template isNumber(t: typedesc[SomeFloat]): string = "Maybe, could be NaN."
- echo "is int a number? ", isNumber(int)
- echo "is float a number? ", isNumber(float)
- echo "is RootObj a number? ", isNumber(RootObj)
传递 typedesc 几乎完全相同,只是因为宏没有一般地实例化。 类型表达式简单地作为 NimNode 传递给宏,就像其他所有东西一样。
- import macros
- macro forwardType(arg: typedesc): typedesc =
- # ``arg`` 是 ``NimNode`` 类型
- let tmp: NimNode = arg
- result = tmp
- var tmp: forwardType(int)