模板的洁净性
默认情况下,模板是 hygienic “洁净”的: 模板内局部声明的标识符,不能在实例化上下文中访问:
template newException* (exceptn: typedesc, message: string): untyped =
var
e: ref exceptn # e 在这里被隐式地 gensym
new(e)
e.msg = message
e
# 允许这样写:
let e = "message"
raise newException(IoError, e)
模板中声明的符号是否向实例所处作用域公开取决于 inject 和 gensym 编译指示。被 gensym 编译指示标记的符号不会公开,而 inject 编译指示则反之。
type , var, let 和 const 等实体符号默认是 gensym,proc,iterator,converter,template,macro 等默认是 inject。 然而,如果实体的名称是由模板参数传入的,那么会标记为 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 模板中没有作用。
标记为 gensym 的符号既不能作为 field 用在 x.field 语义中,也不能用于 ObjectConstruction(field: value) 和 namedParameterCall(field = value) 等语义构造。
其原因在于要让以下代码:
type
T = object
f: int
template tmp(x: T) =
let f = 34
echo x.f, T(f: 4)
按预期执行。
但是这意味着 gensym 生成的符号无法用于方法调用语法:
template tmp(x) =
type
T {.gensym.} = int
echo x.T # 不可以,应该使用: 'echo T(x)' 。
tmp(12)
当前内容版权归 vectorworkshopbaoerjie 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 vectorworkshopbaoerjie .