将字符串内插值传递给宏
Passing string interpolated values into macro
我对这段代码的问题是当传递一个内插字符串时宏失败:
macro t(a, b, c)
quote
println(:c, " = " , $c)
($a, $b, $c)
end
end
function test()
# works:
@t 1 2 3
# doesn't work:
x = π
@t 1 2 "x is $x"
end
test()
test()
c = 3 # works
ERROR: UndefVarError: x not defined
因此在 t
内插值 x
值不可用。是否有解决方案,或者在这里使用宏只是个坏主意?
此类宏的计算方式是,任何非宏函数本身局部的变量名都被视为全局变量名。没有使用宏点的调用范围。
所以这有效:
macro t(a, b, c)
quote
println(:c, " = " , $c)
($a, $b, $c)
end
end
function test()
# works:
@t 1 2 3
x = π # this x is not seen inside the macro's scope
@t 1 2 "x is $x"
end
x = 2π # this one is global
test()
为了达到你想要的效果,你需要使用 esc
:
macro t(a, b, c)
quote
local a1 = $(esc(a))
local b1 = $(esc(b))
local c1 = $(esc(c))
println(:c, " = ", c1)
(a1, b1, c1)
end
end
请注意,我定义了变量 a1
、b1
和 c1
一次,然后重新使用它们。原因是如果你写了类似这样的东西:
macro t(a, b, c)
quote
println(:c, " = ", $(esc(c)))
($(esc(a)), $(esc(b)), $(esc(c)))
end
end
这是很自然的事情(或者可能不是 :)),你会遇到问题,因为 c
会被评估两次,例如。在这个例子中:
julia> macro t(a, b, c)
quote
println(:c, " = ", $(esc(c)))
($(esc(a)), $(esc(b)), $(esc(c)))
end
end
@t (macro with 1 method)
julia> function test()
@t 1 2 rand()
end
test (generic function with 1 method)
julia> test()
c = 0.03771143425073453
(1, 2, 0.1819496773810383)
请注意,打印了不同的值并返回了不同的值。此问题存在于您的原始宏中(即使它使用@Bill 指出的全局变量):
julia> macro t(a, b, c)
quote
println(:c, " = " , $c)
($a, $b, $c)
end
end
@t (macro with 1 method)
julia> @t 1 2 rand()
c = 0.7021554643798531
(1, 2, 0.6363717837673994)
总的来说,我认为 @code_lowered
和 @macroexpand
宏在您使用元编程调试代码时会很有用。
我对这段代码的问题是当传递一个内插字符串时宏失败:
macro t(a, b, c)
quote
println(:c, " = " , $c)
($a, $b, $c)
end
end
function test()
# works:
@t 1 2 3
# doesn't work:
x = π
@t 1 2 "x is $x"
end
test()
test()
c = 3 # works
ERROR: UndefVarError: x not defined
因此在 t
内插值 x
值不可用。是否有解决方案,或者在这里使用宏只是个坏主意?
此类宏的计算方式是,任何非宏函数本身局部的变量名都被视为全局变量名。没有使用宏点的调用范围。
所以这有效:
macro t(a, b, c)
quote
println(:c, " = " , $c)
($a, $b, $c)
end
end
function test()
# works:
@t 1 2 3
x = π # this x is not seen inside the macro's scope
@t 1 2 "x is $x"
end
x = 2π # this one is global
test()
为了达到你想要的效果,你需要使用 esc
:
macro t(a, b, c)
quote
local a1 = $(esc(a))
local b1 = $(esc(b))
local c1 = $(esc(c))
println(:c, " = ", c1)
(a1, b1, c1)
end
end
请注意,我定义了变量 a1
、b1
和 c1
一次,然后重新使用它们。原因是如果你写了类似这样的东西:
macro t(a, b, c)
quote
println(:c, " = ", $(esc(c)))
($(esc(a)), $(esc(b)), $(esc(c)))
end
end
这是很自然的事情(或者可能不是 :)),你会遇到问题,因为 c
会被评估两次,例如。在这个例子中:
julia> macro t(a, b, c)
quote
println(:c, " = ", $(esc(c)))
($(esc(a)), $(esc(b)), $(esc(c)))
end
end
@t (macro with 1 method)
julia> function test()
@t 1 2 rand()
end
test (generic function with 1 method)
julia> test()
c = 0.03771143425073453
(1, 2, 0.1819496773810383)
请注意,打印了不同的值并返回了不同的值。此问题存在于您的原始宏中(即使它使用@Bill 指出的全局变量):
julia> macro t(a, b, c)
quote
println(:c, " = " , $c)
($a, $b, $c)
end
end
@t (macro with 1 method)
julia> @t 1 2 rand()
c = 0.7021554643798531
(1, 2, 0.6363717837673994)
总的来说,我认为 @code_lowered
和 @macroexpand
宏在您使用元编程调试代码时会很有用。