Julia 可变结构体中的可变字段名

4
我希望能够使用变量从 Julia 中的可变结构体中获取字段。
例如:
mutable struct myType
    my_field1::Int = 1
    my_field2::Int = 2
    my_field3::Int = 3
end

现在,让我们假设您使用 struct_instance = myType() 声明了一个特定的结构体实例。

如何以变量的方式从此可变结构体实例中提取字段的值?

假设您想使用for循环将my_struct.field[X]的值分配给一个变量,以便您当前访问的特定字段取决于变量X:

foo = zeros(Int64, 3)
for X = 1:3
    foo(X) = struct_instance.field[X]
end

我不知道如何实际实现上面的for循环 - 我上面写的只是伪代码。例如在MATLAB中,您可以使用以下符号:

foo = zeros(1,3)
for x = 1:3
    foo(x) = struct_instance.(sprintf('field%d',x))
end

提前致谢。


1
在这种情况下,您想要做的是在结构体中创建一个单一变量:my_field并使该元素成为Vector{Int} - Oscar Smith
2个回答

6
从结构体中获取字段的函数是fieldnames:
julia> mutable struct A
       x
       y
       z
       end

julia> fieldnames(A)
(:x, :y, :z)

为了以编程方式设置这些字段值,您可以使用 setproperty!
julia> a = A(1,1,1)
A(1,1,1)

julia> a.x
1

julia> setproperty!(a, :x, 2)
2

julia> a.x
2

通过使用 for 循环:

julia> for i in fieldnames(A)
           setproperty!(a, i, 3)
       end

julia> a
A(3,3,3)

2
另外值得一提的是 propertynamesgetproperty - 通过它们,你可以模仿所有字段的行为。此外,要显式地使用 _字段_,你可以使用 getfieldsetfield!,它们通常不会被重载。这允许你访问结构体的字段,而不仅仅是公开的属性。 - Anshul Singhvi
1
这很有帮助,但不完全是我想象中的。我想解决方案涉及使用getproperty!()并传递一个字符串。我的意思是使用变量生成一个字符串(我知道它将是一个可行的字段名),然后使用该字符串本身来访问字段(或属性,我猜?)。在MATLAB中,这称为动态字段名。我不是使用变量更改要访问的字段,而是使用变量生成字段本身的名称。然后,我使用该变量字段名称(生成为字符串,我猜?)来访问结构体的字段。 - Conor

5
为了使你示例代码开头的代码能够工作,你需要使用Paramaters包,否则你将无法设置默认值(你示例中的代码会抛出一个错误)。我经常在需要使用struct来表示一堆变量的情况下使用它。
using Parameters

@with_kw mutable struct MyType
    my_field1::Int = 1
    my_field2::Int = 2
    my_field3::Int = 3
end

这还会生成一组关键字方法,用于在创建对象时以编程方式设置字段。请查看以下代码:
julia> vals = [Symbol("my_field$i") =>10i for i in 2:3 ]
2-element Array{Pair{Symbol,Int64},1}:
 :my_field2 => 20
 :my_field3 => 30

julia> MyType(;vals...)
MyType
  my_field1: Int64 1
  my_field2: Int64 20
  my_field3: Int64 30

我们在这里创建了一组字段名称,并且在创建对象时使用它。当您考虑使用不可变对象而不是可变对象时,这种方法特别有用(不可变对象始终更快)。
您可以使用 setfield! 来改变对象的值:
julia> for i in 1:2
           setfield!(m,Symbol("my_field$i"), 20i)
       end
julia> m
MyType
  my_field1: Int64 20
  my_field2: Int64 40
  my_field3: Int64 30

我认为,如果你来自Matlab,这将是布局你的struct的最便捷方式。


谢谢!这正是我在寻找的——基本上,可以将字符串作为输入的“Symbol”类型是我所缺失的关键。另外,关于使用不可变对象和可变对象:如果字段本身是我想要随时间填充的数组,我仍然可以使用不可变对象吗?我使用了可变对象,因为我希望在我的应用程序中随时更新字段的值。 - Conor
2
顺便说一下,您也可以通过数字索引字段,例如 setfield(m, 2, 15) - tholy
1
@user13259528 是的,您可以变异不可变struct的一部分的Array元素,但不能变异Array字段本身。Julia使用传统“通过共享”的约定 - 可以查看此线程:https://dev59.com/vLbna4cB1Zd3GeqPdpqR - Przemyslaw Szufel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接