模板卫生
每个默认模板是 卫生的: 无法在实例化上下文中访问模板中声明的本地标识符:
- template newException*(exceptn: typedesc, message: string): untyped =
- var
- e: ref exceptn # e是隐式符号生成
- new(e)
- e.msg = message
- e
- # 所以这是可以的:
- let e = "message"
- raise newException(IoError, e)
是否在模板中声明的符号是否暴露给实例化范围由 inject 和 gensym 编译指示控制,gensym的符号不会暴露而是注入。 type, var, let 和 const 的实体符号默认是 gensym ,proc
, iterator, converter, template, macro 是 inject. 但是,如果实体的名称作为模板参数传递,则它是一个注入符号:
- template withFile(f, fn, mode: untyped, actions: untyped): untyped =
- block:
- var f: File # 因为'f'是模板形参,它被隐式注入
- ...
- withFile(txt, "ttempl3.txt", fmWrite):
- txt.writeLine("line 1")
- txt.writeLine("line 2")
inject 和 gensym 编译指示是二等注释;它们在模板定义之外没有语义,不能被抽象:
- {.pragma myInject: inject.}
- template t() =
- var x {.myInject.}: int # 不行
为了摆脱模板中的卫生,可以为模板使用 dirty 编译指示。 inject 和 gensym 在 dirty 模板中没有意义。