我想在宏中创建一个新变量。我的代码可以简化为:
macro test()
%p = "a = 3"
%p
end
test()
puts(a)
但我收到错误undefined local variable or method 'a'
我尝试将%p
包裹在{{ }}
或{% %}
中,但它不会编译(“unexpected token: %
”)
修改
以下是一些背景信息。
我经常不得不使用两个带有一些公共字段的命名元组,然后将这些字段转换为JSON并发送给不同的客户端。
a = {x: xx, y: yy, w: ww}
b = {x: xx, y: yy, z: zz}
目前我正在重复写两篇文章。 ww,xx,yy,zz的值在编译时是未知的。我想在编译时调用一个宏来替换它。
我想出了以下代码,它创建了我当前手动输入的代码行:
macro merge(common, aOnly, bOnly)
# Start, middle and end parts of target instructions
%p1a = "a = {"
%p1b = "b = {"
%p2 = ""
%p2a = ""
%p2b = ""
%p3 = "}"
# Creating the middle part
{% for key, value in common %}
%p2 = %p2 + "{{key.id}}" + ": " + "{{value}}" + ','
{% end %}
%p2a = %p2
{% for key, value in aOnly %}
%p2a = %p2a + "{{key.id}}" + ": " + "{{value}}" + ','
{% end %}
%p2b = %p2
{% for key, value in bOnly %}
%p2b = %p2b + "{{key.id}}" + ": " + "{{value}}" + ','
{% end %}
# Removing unneeded comma
%p2a = %p2a.chomp(",")
%p2b = %p2b.chomp(",")
# Display
puts(%p1a + %p2a + %p3)
puts(%p1b + %p2b + %p3)
# Definition of new variables
%p1a + %p2a + %p3
%p1b + %p2b + %p3
end
merge({x: xx, y: yy}, {w: ww}, {z: zz})
答案 0 :(得分:3)
这里的主要问题是对%names
的误解。这不是使指令编译时间的构造。编写%a = 5
与编写guaranteed_unique_name = 5
相同 - 这是一种避免干扰同一范围内可能存在的其他变量的方法,但它仍然是正常的运行时变量赋值。
构造字符串然后在编译时输出它们并不是使用宏的可行方法,并且它几乎总是不可能,因为您无法将不同的值重新分配给宏变量。但是这里有一个例子,如果它确实有效,它仍然会尝试使用你的方法与字符串:
macro merge(common, aOnly, bOnly)
# Start, middle and end parts of target instructions
{%
p1a = "a = {"
p1b = "b = {"
p2 = ""
p2a = ""
p2b = ""
p3 = "}"
%}
# Creating the middle part
{% for key, value in common %}
{% p2 = p2 + "#{key.id}: #{value}," %}
{% end %}
{% p2a = p2 %}
{% for key, value in aOnly %}
{% p2a += "#{key.id}: #{value}," %}
{% end %}
{% p2b = p2 %}
{% for key, value in bOnly %}
{% p2b += "#{key.id}: #{value}," %}
{% end %}
# Removing unneeded comma
{% p2a = p2a.chomp(",") %}
{% p2b = p2b.chomp(",") %}
# Definition of new variables
{{(p1a + p2a + p3).id}}
{{(p1b + p2b + p3).id}}
end
merge({x: xx, y: yy}, {w: ww}, {z: zz})
现在我将用更常见的结构重写你的例子:
macro merge(common, a_only, b_only)
a = {
{% for key, value in common %}
{{key}}: {{value}},
{% end %}
{% for key, value in a_only %}
{{key}}: {{value}},
{% end %}
}
b = {
{% for key, value in common %}
{{key}}: {{value}},
{% end %}
{% for key, value in b_only %}
{{key}}: {{value}},
{% end %}
}
end
merge({x: "a", y: 5}, {w: "b"}, {z: 7})
pp a, b
正如您所看到的,放在宏体中的普通代码是运行时代码,而{% %}
和{{ }}
中的内容在编译时执行。您可以编写时间循环并将它们与普通代码行交织在一起,以自然地创建复杂的代码。
希望能回答问题标题“为Crystal宏中的新变量赋值”:为运行时变量分配一些内容,就像在宏中输出任何运行时代码一样 - 你只需写出来与a = 5
类似,因为默认情况下宏输出运行时代码,并且只有{%
和{{
分隔编译时构造。
要回复评论,这里可能是一个更为惯用的版本,它甚至可以说明临时/唯一的变量名称。它使用它们来创建元组,然后宏执行的结果是那些可以方便地解压缩的元组,而不是依赖于副作用,这很少发生。
macro merge(common, a_only, b_only)
%a = {
{% for key, value in common %}
{{key}}: {{value}},
{% end %}
{% for key, value in a_only %}
{{key}}: {{value}},
{% end %}
}
%b = {
{% for key, value in common %}
{{key}}: {{value}},
{% end %}
{% for key, value in b_only %}
{{key}}: {{value}},
{% end %}
}
{ %a, %b }
end
first, second = merge({x: "a", y: 5}, {w: "b"}, {z: 7})
puts first