Julia struct

时间:2018-01-23 12:05:25

标签: struct julia immutability mutable

我无法在stackoverflow和Julia文档中找到以下“设计问题”的答案:

假设我想定义以下对象

struct Person
birthplace::String
age::Int
end

由于Person是不可变的,我很高兴没有人可以更改所创建的任何birthplace Person,但这也意味着当时间过去了,我无法更改{ {1}}要么......

另一方面,如果我将类型age定义为

Person

我现在可以制作mutable struct Person birthplace::String age::Int end ,但我没有age之前的安全性,任何人都可以访问并更改它。

到目前为止我找到的解决方法如下

birthplace

显然struct Person birthplace::String age::Vector{Int} end 是1个元素age 我发现这个解决方案非常难看并且绝对不是最理想的,因为我每次都必须使用方括号访问年龄。

还有其他更优雅的方法在对象中同时拥有不可变字段和可变字段吗?

也许问题在于我错过了在Vector内拥有所有可变或不可变的真正价值。如果是这样的话,你能解释一下吗?

2 个答案:

答案 0 :(得分:12)

对于这个特殊的例子,最好存储生日,而不是年龄,因为生日也是不可变的,并且很容易根据该信息计算年龄,但也许这只是一个玩具的例子。

  

我发现这个解决方案非常难看,而且我必须这样做绝对不是最理想的   每次都用方括号访问年龄。

通常你会定义一个getter,即你使用age(p::Person) = p.age[1]之类的东西,而不是直接访问该字段。有了这个,你就可以避免括号中的“丑陋”。

在这种情况下,我们只想存储单个值,也可以使用Ref(或者可能是0维Array),例如:

struct Person
    birthplace::String
    age::Base.RefValue{Int}
end
Person(b::String, age::Int) = Person(b, Ref(age))
age(p::Person) = p.age[]

用法:

julia> p = Person("earth", 20)
Person("earth", 20)

julia> age(p)
20

答案 1 :(得分:6)

您已经收到了一些有趣的答案,以及#34;玩具示例" case,我喜欢存储出生日期的解决方案。但对于更一般的情况,我可以想到另一种可能有用的方法。将Age定义为自己的可变结构,将Person定义为不可变结构。那就是:

julia> mutable struct Age ; age::Int ; end

julia> struct Person ; birthplace::String ; age::Age ; end

julia> x = Person("Sydney", Age(10))
Person("Sydney", Age(10))

julia> x.age.age = 11
11

julia> x
Person("Sydney", Age(11))

julia> x.birthplace = "Melbourne"
ERROR: type Person is immutable

julia> x.age = Age(12)
ERROR: type Person is immutable

请注意,我无法更改Person的任何一个字段,但我可以通过直接访问可变结构age中的Age字段来更改年龄。您可以为此定义一个访问者函数,即:

set_age!(x::Person, newage::Int) = (x.age.age = newage)

julia> set_age!(x, 12)
12

julia> x
Person("Sydney", Age(12))

另一个答案中讨论的Vector解决方案没有任何问题。它基本上完成了同样的事情,因为数组元素是可变的。但我认为上述解决方案更整洁。