奇妙なセマンティクスを避けるために、変更可能な参照型のフィールドを保持するすべての構造体は、次の 2 つのいずれかを行う必要があります。
- その観点から、フィールドの内容はオブジェクトを「保持」するのではなく、単にオブジェクトを識別するのに役立つことを非常に明確にする必要があります。たとえば、`KeyValuePair<String, Control>` は完全に合理的な型です。`Control` は可変ですが、そのような型によって参照されるコントロールのIDは不変になるからです。
- 変更可能なオブジェクトは、値の型によって作成されたものである必要があり、その外部に公開されることはありません。さらに、不変オブジェクトに対して実行されるすべての変更は、オブジェクトへの参照が構造体のフィールドに格納される前に実行する必要があります。
他の人が指摘したように、構造体が配列をシミュレートできるようにする1つの方法は、配列を保持し、要素が変更されるたびにその配列の新しいコピーを作成することです。もちろん、そのようなことはとてつもなく遅くなります。別のアプローチは、最後のいくつかの変更リクエストのインデックスと値を格納するロジックを追加することです。配列を読み取ろうとするたびに、値が最近書き込まれた値の 1 つであるかどうかを確認し、そうである場合は、配列内の値ではなく、構造体に格納されている値を使用します。構造体内のすべての「スロット」が埋まったら、配列のコピーを作成します。このアプローチは、更新が多くの異なる要素にヒットした場合に配列を再生成するのに対して、せいぜい「のみ」一定の速度向上を提供しますが、更新の大部分が少数の要素にヒットした場合に役立つ可能性があります。
Another approach when updates are likely to have a high special concentration, but hit too many elements for them to fit entirely within a struct, would be to keep a reference to a "main" array, as well as an "updates" array along with an integer indicating what part of the main array the "updates" array represents. Updates would often require regeneration of the "updates" array, but that could be much smaller than the main array; if the
"updates" array gets too big, the main array can be regenerated with changes represented by the "updates" array incorporated within it.
これらのアプローチの最大の問題は、struct
効率的なコピーを可能にしながら一貫した値型のセマンティクスを提示するように設計することはできますが、構造体のコードを一目見ただけではそれがほとんど明らかではないことです (plain-old と比較して) -data 構造体 (構造体に呼び出された public フィールドがあるという事実により、Foo
どのように動作するかが非常に明確にFoo
なります)。