web-dev-qa-db-ja.com

Julia構造体の可変フィールド

次の「設計上の問題」に対するstackoverflowとJuliaのドキュメントの両方で答えが見つかりませんでした。

次のオブジェクトを定義したいとしましょう

struct Person
birthplace::String
age::Int
end

Personは不変であるため、作成されたbirthplacePersonを誰も変更できないことを嬉しく思います。それでも、時間が経つと、ageも変更できないことを意味します...

一方、タイプPersonを次のように定義すると

mutable struct Person
birthplace::String
age::Int
end

これでageにすることができますが、以前のbirthplaceの安全性がなく、誰でもアクセスして変更できます。

これまでに見つけた回避策は次のとおりです

struct Person
birthplace::String
age::Vector{Int}
end

ここで、明らかにageは1要素のVectorです。
毎回角括弧で年齢にアクセスする必要があるため、このソリューションは非常に醜く、間違いなく最適ではないと思います。

オブジェクトに不変フィールドと可変フィールドの両方を含める、他のよりエレガントな方法はありますか?

おそらく問題は、struct内ですべてを可変または不変にするという真の価値を見逃していることです。もしそうなら、それを説明してもらえますか?

15
stefabat

この特定の例では、生年月日も不変であり、その情報から年齢を計算するのは簡単なので、年齢よりも生年月日を保存する方がよいようですが、これは単なるおもちゃの例です。


毎回角括弧で年齢にアクセスする必要があるため、このソリューションは非常に醜く、間違いなく最適ではないと思います。

通常、ゲッターを定義します。つまり、フィールドに直接アクセスする代わりに使用する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
14
fredrikekre

あなたはいくつかの興味深い答えを受け取りました、そして「おもちゃの例」の場合、私は生年月日を保存する解決策が好きです。しかし、より一般的なケースでは、役立つ可能性のある別のアプローチを考えることができます。 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のどちらのフィールドも変更できませんが、可変構造体ageAgeフィールドに直接アクセスすることで年齢を変更できることに注意してください。このためのアクセサ関数を定義できます。

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

Julia> set_age!(x, 12)
12

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

別の回答で説明されているVectorソリューションに問題はありません。配列要素は変更可能であるため、基本的に同じことを実行しています。しかし、私は上記の解決策はより良いと思います。

6
Colin T Bowers