引用不带点符号的结构字段(在Julia中)
在Julia中,我定义了一个类型,我需要编写一些处理该类型字段的函数。有些函数包含复杂的公式,到处使用字段访问点表示法会变得很混乱。因此,我最终将字段值放入局部变量以提高可读性。它工作得很好,但是有没有什么聪明的方法可以避免键入所有引用不带点符号的结构字段(在Julia中),julia,Julia,在Julia中,我定义了一个类型,我需要编写一些处理该类型字段的函数。有些函数包含复杂的公式,到处使用字段访问点表示法会变得很混乱。因此,我最终将字段值放入局部变量以提高可读性。它工作得很好,但是有没有什么聪明的方法可以避免键入所有a=foo.a行,或者让Julia parsea作为foo.a等 struct Foo a::Real b::Real c::Real end # this gets hard to read function bar(foo::Foo)
a=foo.a
行,或者让Julia parsea
作为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
由于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)
function bar(foo::Foo)
# something clever!
@unpack a, b, c = f
a + b + c + a*b - b*c
end
请注意,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
尽管这确实需要您再次提及字段名称,但它有两个潜在优势:
结构
并重命名字段的情况下,访问字段的所有代码都将保持不变(只要字段顺序不变,或者迭代
实现被更改以反映新的对象内部结构)a
,而不是使用完整的apples
字段名)如果字段名不能重复很重要,您可以定义一个宏来生成所需的变量(
a=foo.a;b=foo.b;c=foo.c
);但是,这可能会让代码的读者更加困惑,并且缺少上面列出的优点。从Julia 1.6开始,此包中的宏看起来很相关:
语法如下所示:
Base.iterate(foo::Foo, state = 1) = state > 3 ? nothing : (getfield(foo, state), state + 1)
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
这是合并的拉取请求:中有一个
@unpack
宏。可能是重复的谢谢,两个选项都很好。版本0.7的语法特别吸引人,所以我可能会等到使用了0.7之后再进行更改。