首页 > 解决方案 > 参考不带点符号的结构字段(在 Julia 中)

问题描述

在 Julia 中,我定义了一个类型,我需要编写一些函数来处理该类型的字段。一些函数包含复杂的公式,并且到处使用字段访问点表示法会变得很混乱。所以我最终将字段值放入局部变量中以提高可读性。它工作得很好,但是有没有一些聪明的方法可以避免输入所有的a=foo.a行或让 Julia 解析afoo.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 中,可以通过迭代将对象“解包”为多个变量:

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

尽管这确实需要您再次提及字段名称,但它具有两个潜在的优势:

  1. 如果您struct被重构并且字段被重命名,所有访问字段的代码都将保持不变(只要字段顺序没有改变或iterate实现被改变以反映新的对象内部)。
  2. 较长的字段名称可以缩写。apples(即,您可以选择使用,而不是使用完整的字段名称a。)

如果字段名称不重复很重要,您可以定义一个宏来生成所需的变量(a = foo.a; b = foo.b; c = foo.c);但是,这可能会让您的代码的读者更加困惑,并且缺乏上面列出的优势。


推荐阅读