函数的 Julia Do 语法是如何工作的?
How does the Julia Do Syntax for functions work?
我已经看到 here do
语法可以用作编写 map()
函数的更方便的方法,但我不明白例如在链接的 julia 文档中显示的示例中:
open("outfile", "w") do io
write(io, data)
end
适用于 'open'
的以下函数定义
function open(f::Function, args...)
io = open(args...)
try
f(io)
finally
close(io)
end
end
do
究竟如何将 io
和 write(io,data)
传递给 open
和 f(io)
的实际功能? do
块的函数是否必须具有相同的 name/be 多分派才能使 do
块工作?
纯语法转换
func(x) do y
body
end
相当于
func(y -> body, x)
或
tmp = y -> body
func(tmp, x)
如果你愿意的话,即 do
块定义了一个作为第一个参数传递的匿名函数。当然,要实现这一点,需要存在具有匹配签名的 func
方法,例如 func(f::Function, ...) = ...
(或简单地 func(f, ...) = ...
)。
您可以使用 Meta.@lower
:
检查实际情况
julia> Meta.@lower func(x) do y
print(y)
end
:($(Expr(:thunk, CodeInfo(
@ none within `top-level scope'
1 ─ $(Expr(:thunk, CodeInfo(
@ none within `top-level scope'
1 ─ global var"#1#2"
│ const var"#1#2"
│ %3 = Core._structtype(Main, Symbol("#1#2"), Core.svec(), Core.svec(), false, 0)
│ var"#1#2" = %3
│ Core._setsuper!(var"#1#2", Core.Function)
│ Core._typebody!(var"#1#2", Core.svec())
└── return nothing
)))
│ %2 = Core.svec(var"#1#2", Core.Any)
│ %3 = Core.svec()
│ %4 = Core.svec(%2, %3, $(QuoteNode(:(#= REPL[1]:2 =#))))
│ $(Expr(:method, false, :(%4), CodeInfo(
@ REPL[1]:2 within `none'
1 ─ %1 = print(y)
└── return %1
)))
│ #1 = %new(var"#1#2")
│ %7 = #1
│ %8 = func(%7, x)
└── return %8
))))
不幸的是,输出是匿名函数的实现细节的乱码:代码定义了一个新结构 (%3
),使用 [= 的主体使其可调用 (%4
) 14=] 块,创建它的一个实例 (%7
),最后调用 func(%7, x)
.
如果它对任何人有帮助,我还通过摆弄@fredrikekre 通过这个例子写的一般内容发现:
function func(blah::Function,baz,foo)
blah([baz,foo])
End
您可以将其称为以下任何一种
func("a", "b") do zzz
vcat(uppercase.(zzz),"C")
end
func(zzz->vcat(uppercase.(zzz),"C"),"a", "b")
两者产生相同的输出
3-element Vector{String}:
"A"
"B"
"C"
我已经看到 here do
语法可以用作编写 map()
函数的更方便的方法,但我不明白例如在链接的 julia 文档中显示的示例中:
open("outfile", "w") do io
write(io, data)
end
适用于 'open'
的以下函数定义function open(f::Function, args...)
io = open(args...)
try
f(io)
finally
close(io)
end
end
do
究竟如何将 io
和 write(io,data)
传递给 open
和 f(io)
的实际功能? do
块的函数是否必须具有相同的 name/be 多分派才能使 do
块工作?
纯语法转换
func(x) do y
body
end
相当于
func(y -> body, x)
或
tmp = y -> body
func(tmp, x)
如果你愿意的话,即 do
块定义了一个作为第一个参数传递的匿名函数。当然,要实现这一点,需要存在具有匹配签名的 func
方法,例如 func(f::Function, ...) = ...
(或简单地 func(f, ...) = ...
)。
您可以使用 Meta.@lower
:
julia> Meta.@lower func(x) do y
print(y)
end
:($(Expr(:thunk, CodeInfo(
@ none within `top-level scope'
1 ─ $(Expr(:thunk, CodeInfo(
@ none within `top-level scope'
1 ─ global var"#1#2"
│ const var"#1#2"
│ %3 = Core._structtype(Main, Symbol("#1#2"), Core.svec(), Core.svec(), false, 0)
│ var"#1#2" = %3
│ Core._setsuper!(var"#1#2", Core.Function)
│ Core._typebody!(var"#1#2", Core.svec())
└── return nothing
)))
│ %2 = Core.svec(var"#1#2", Core.Any)
│ %3 = Core.svec()
│ %4 = Core.svec(%2, %3, $(QuoteNode(:(#= REPL[1]:2 =#))))
│ $(Expr(:method, false, :(%4), CodeInfo(
@ REPL[1]:2 within `none'
1 ─ %1 = print(y)
└── return %1
)))
│ #1 = %new(var"#1#2")
│ %7 = #1
│ %8 = func(%7, x)
└── return %8
))))
不幸的是,输出是匿名函数的实现细节的乱码:代码定义了一个新结构 (%3
),使用 [= 的主体使其可调用 (%4
) 14=] 块,创建它的一个实例 (%7
),最后调用 func(%7, x)
.
如果它对任何人有帮助,我还通过摆弄@fredrikekre 通过这个例子写的一般内容发现:
function func(blah::Function,baz,foo)
blah([baz,foo])
End
您可以将其称为以下任何一种
func("a", "b") do zzz
vcat(uppercase.(zzz),"C")
end
func(zzz->vcat(uppercase.(zzz),"C"),"a", "b")
两者产生相同的输出
3-element Vector{String}:
"A"
"B"
"C"