do 符号神奇地修复了一个否则被拒绝的表达式作为参数

do notation magically fixes an otherwise refused expression as argument

在 Nim 模板中:作为 的后续行动,我想到了通过使用重载来解决默认参数不可用的问题,甚至在这种情况下,使用简单包装。不过,如果没有再次引起粉丝关注就太好了,让我分享一下:

请注意 bodyFinally 现在是一个硬性(必须指定)参数。

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

# we add a convenience helper with 2 args here.
template tpl2(x: bool, body: untyped): void =
  tpl(x) do:
    body
  do:
    discard

#call site:
var r: int
tpl2(true) do:
  r = 2

很酷(有效)。虽然这不是我第一次尝试 tpl2;这是:

template tpl2(x: bool, body: untyped): void =
  tpl(x, body, discard)

因为那是 do 无论如何都应该重写的东西。除了我们得到:

Error: expression expected, but found 'keyword discard'

那是怎么回事?

解释原因有点复杂,但你可以这样写重载:

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

template tpl(x: bool, body: untyped): void =
  tpl(x, body, (discard))

var r = 1

tpl(false):
  r = 2

echo r

tpl(true):
  r = 3

echo r

额外的括号会触发一个特殊的解析规则,生成 nkStmtListExpr AST 节点,这是此处模板的有效输入。此构造通常用于 C-style if 语句,其中包含一个赋值后跟一个 NULL-test:

if (let f = fopen(...); f != 0):
  # do something with `f`

正如预期的那样,运行 上述程序的输出将是:

1
3