模板卫生

每个默认模板是 卫生的: 无法在实例化上下文中访问模板中声明的本地标识符:

  1. template newException*(exceptn: typedesc, message: string): untyped =
  2. var
  3. e: ref exceptn # e是隐式符号生成
  4. new(e)
  5. e.msg = message
  6. e
  7.  
  8. # 所以这是可以的:
  9. let e = "message"
  10. raise newException(IoError, e)

是否在模板中声明的符号是否暴露给实例化范围由 inject 和 gensym 编译指示控制,gensym的符号不会暴露而是注入。 type, var, letconst 的实体符号默认是 gensymproc, iterator, converter, template, macroinject. 但是,如果实体的名称作为模板参数传递,则它是一个注入符号:

  1. template withFile(f, fn, mode: untyped, actions: untyped): untyped =
  2. block:
  3. var f: File # 因为'f'是模板形参,它被隐式注入
  4. ...
  5.  
  6. withFile(txt, "ttempl3.txt", fmWrite):
  7. txt.writeLine("line 1")
  8. txt.writeLine("line 2")

injectgensym 编译指示是二等注释;它们在模板定义之外没有语义,不能被抽象:

  1. {.pragma myInject: inject.}
  2.  
  3. template t() =
  4. var x {.myInject.}: int # 不行

为了摆脱模板中的卫生,可以为模板使用 dirty 编译指示。 injectgensymdirty 模板中没有意义。