引用不带点符号的结构字段(在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)

在Julia中,我定义了一个类型,我需要编写一些处理该类型字段的函数。有些函数包含复杂的公式,到处使用字段访问点表示法会变得很混乱。因此,我最终将字段值放入局部变量以提高可读性。它工作得很好,但是有没有什么聪明的方法可以避免键入所有
a=foo.a
行,或者让Julia parse
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

由于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之后再进行更改。