模板表达式的默认参数

v.o*_*dou 2 templates default-arguments nim-lang

如果我想制作一个可以接受 2 个untyped参数的模板,并通过do符号传递它们,当我省略第二个参数时,do我希望有一种方法以参数的默认值的形式指定回退。像这样:

template tpl(x: bool, body: untyped, bodyFinally: untyped): void =
  if x: body
  else: bodyFinally

#call site:
var r: int
tpl(true) do:
  r = 2
do:
  raise newException(Exception, "")
Run Code Online (Sandbox Code Playgroud)

这有效,但是:

template tpl(x: bool, body: untyped, bodyFinally: untyped = discard): void =
  # same rest
Run Code Online (Sandbox Code Playgroud)

错误:应有表达式,但发现“关键字丢弃”

不接受默认值,消息很奇怪,discard是不是表达式。

尝试解决方法:

template tpl(x: bool, body: untyped, bodyFinally: untyped = proc()): void =
  # same rest
Run Code Online (Sandbox Code Playgroud)

然后我们得到:

错误:表达式 'proc ()' 的类型为 'type proc (){.closure.}' 并且必须被丢弃

我已经准备好接受这一点,即使我发现这个discard要求毫无用处,而且是语言的麻烦,因为它迫使我们在像这里这样的通用代码中进行不舒服的体操。

让我们再次编辑:

template tpl(x: bool, body: untyped, bodyFinally: untyped = proc()): void =
  if x: body
  else: discard bodyFinally
Run Code Online (Sandbox Code Playgroud)

现在的结果是:

错误:内部错误:expr(nkProcTy); 未知节点种类

zah*_*zah 5

确实没有办法将代码块描述为默认参数值。有两种可能的解决方法:

1)您可以通过重载模拟默认值:

template tpl(x: bool, body: untyped, bodyFinally: untyped) =
  if x: body
  else: bodyFinally

template tpl(x: bool, body: untyped): void =
  tpl(x) do:
    body
  do:
    discard
Run Code Online (Sandbox Code Playgroud)

第二个重载的另一个较短版本是这样的:

template tpl(x: bool, body: untyped): void =
  tpl(x, body, (discard))
Run Code Online (Sandbox Code Playgroud)

2)您可以使用nil可以在模板中检测到的默认值:

import macros

template tpl(x: bool, body: untyped, bodyFinally: untyped = nil) =
  if x:
    body
  else:
    when astToStr(bodyFinally) == "nil":
      discard
    else:
      bodyFinally
Run Code Online (Sandbox Code Playgroud)

请注意,我不得不用astToStr,因为它不会是能够比较bodyFinallynil用户耗材时,非默认值。