在Julia中,我定义了一个类型,我需要编写一些可用于该类型字段的函数。有些函数包含复杂的公式,并且在各处使用字段访问点表示法会很混乱。因此,我最终将字段值放入局部变量中以提高可读性。效果很好,但是有什么聪明的方法可以避免必须键入所有a=foo.a
行或让Julia将a
解析为foo.a
等?
struct Foo
a::Real
b::Real
c::Real
end
# this gets hard to read
function bar(foo::Foo)
foo.a + foo.b + foo.c + foo.a*foo.b - foo.b*foo.c
end
# this is better
function bar(foo::Foo)
a = foo.a
b = foo.b
c = foo.c
a + b + c + a*b - b*c
end
# this would be great
function bar(foo::Foo)
something clever
a + b + c + a*b - b*c
end
答案 0 :(得分:6)
由于Julia通常鼓励使用通用接口与字段进行交互,而不是直接访问字段,因此,实现此目标的相当自然的方法是通过迭代解包。在Julia中,可以通过迭代将对象“拆包”为多个变量:
julia> x, y = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> x
1
julia> y
2
我们可以为诸如Foo
之类的自定义对象实现这种迭代协议。在v0.7中,它看起来像:
Base.iterate(foo::Foo, state = 1) = state > 3 ? nothing : (getfield(foo, state), state + 1)
请注意,3是硬编码的(基于Foo
中的字段数),可以用fieldcount(Foo)
代替。现在,您只需按以下步骤“解压缩” Foo
的实例即可:
julia> a, b, c = Foo("one", 2.0, 3)
Foo("one", 2.0, 3)
julia> a
"one"
julia> b
2.0
julia> c
3
这可能是功能开始时的“聪明之处”。此外,从v0.7开始,您可以在函数参数本身中解压缩字段:
function bar((a, b, c)::Foo)
a + b + c + a*b - b*c
end
尽管这确实需要您再次提及字段名称,但它具有两个潜在的优点:
struct
并重命名字段的情况下,所有访问字段的代码将保持不变(只要字段顺序不变或iterate
实现被更改反映新对象的内部结构)。apples
,而不是使用完整的a
字段名称。)如果不要重复字段名称很重要,则可以定义一个宏以生成所需的变量(a = foo.a; b = foo.b; c = foo.c
);但是,这可能会使您的代码读者更加困惑,并且缺少上面列出的优点。
答案 1 :(得分:2)
从 Julia 1.6 开始,这个包中的宏看起来很相关:https://github.com/mauro3/UnPack.jl。
语法如下:
function bar(foo::Foo)
# something clever!
@unpack a, b, c = f
a + b + c + a*b - b*c
end
在 Julia 1.7 中,看起来这个特性将与语法一起添加
function bar(foo::Foo)
# something clever!
(; a, b, c) = f
a + b + c + a*b - b*c
end