• 模板卫生

    模板卫生

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

    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 模板中没有意义。