跳至内容

新鲜变量

一旦宏生成代码,它们就会被一个常规的 Crystal 解析器解析,在宏调用上下文中,局部变量被假定为已定义。

通过一个例子可以更好地理解这一点。

macro update_x
  x = 1
end

x = 0
update_x
x # => 1

这有时可能有用,因为它可以避免通过故意读取/写入局部变量来重复代码,但它也可能意外地覆盖局部变量。为了避免这种情况,可以使用 `%name` 声明新鲜变量。

macro dont_update_x
  %x = 1
  puts %x
end

x = 0
dont_update_x # outputs 1
x             # => 0

在上面的例子中,使用 `%x`,我们声明了一个变量,它的名字保证不会与当前作用域中的局部变量冲突。

此外,可以针对某个其他 AST 节点声明新鲜变量,使用 `%var{key1, key2, ..., keyN}`。例如:

macro fresh_vars_sample(*names)
  # First declare vars
  {% for name, index in names %}
    print "Declaring: ", stringify(%name{index}), '\n'
    %name{index} = {{index}}
  {% end %}

  # Then print them
  {% for name, index in names %}
    print stringify(%name{index}), ": ", %name{index}, '\n'
  {% end %}
end

macro stringify(var)
  {{ var.stringify }}
end

fresh_vars_sample a, b, c

# Sample output:
# Declaring: __temp_255
# Declaring: __temp_256
# Declaring: __temp_257
# __temp_255: 0
# __temp_256: 1
# __temp_257: 2

在上面的例子中,声明了三个索引变量,并为它们赋值,然后打印它们,显示它们对应的索引。