ている値型の不変な定義?
-
22-08-2019 - |
質問
ということでしょうが struct
s"は不変でいによる侵入します。
いると考える int
する不変な?
int i = 0;
i = i + 123;
うえました int
を割り当てで i
.何か。
i++;
あしたを考えることができるとしてもストメニューから起動できます。
i = i + 1;
うに struct
Point
?
Point p = new Point(1, 2);
p.Offset(3, 4);
この本当の変更点 (1, 2)
?なで考えられているときのショートカットとして、以下のと Point.Offset()
帰国の新しいか否かで意見が分かれた。
p = p.Offset(3, 4);
その背景とした考えはこれですが、どのような価値の型がない認すると変更可能な?すで見回するかどうかを判定します。がどのようにすることができますことなくアイデンティティ?
ならないようにしたい複雑な推論する検討 ref
パラメータとボクシング.私もその p = p.Offset(3, 4);
を表す不変のほうが良い p.Offset(3, 4);
います。もう残っていない値型の不変な定義?
更新
もあると思う少なくとも二つの概念の関与の可変性の変数またはフィールドの可変性の値に変更します。
public class Foo
{
private Point point;
private readonly Point readOnlyPoint;
public Foo()
{
this.point = new Point(1, 2);
this.readOnlyPoint = new Point(1, 2);
}
public void Bar()
{
this.point = new Point(1, 2);
this.readOnlyPoint = new Point(1, 2); // Does not compile.
this.point.Offset(3, 4); // Is now (4, 6).
this.readOnlyPoint.Offset(3, 4); // Is still (1, 2).
}
}
例のない分野で変更可能な一つ、変更できます。が値型のフィールドの値は、値型に格納される不変の分野で不変でなければならない。い理由の結果-なかったのexspectの読み取り専用の分野の変更.
変数のほかの定数)のbgmの変更可能なるものを示唆する無制限の可変性の値です。
その答えになることを直進いたしますの箇所の問題をもたらしていました。
されます。
public struct Foo
{
public void DoStuff(whatEverArgumentsYouLike)
{
// Do what ever you like to do.
}
// Put in everything you like - fields, constants, methods, properties ...
}
することができる完了版 Foo
および利用例を含め、 ref
パラメータとボクシング-くることはできませんので書き換えてスパイラル破壊部隊入の
foo.DoStuff(whatEverArgumentsYouLike);
と
foo = foo.DoStuff(whatEverArgumentsYouLike);
解決
オブジェクトは不変なのでその場の状態 な変更後のオブジェクト て作成されます。
答え:いいえ、値の種類は不変なのです。 両方の構造体および授業でなければならないと規定されて変更可能なまたは変更できません。 全ての組み合わせが可能です。合構造体やクラスは、非読み取り専用の公共分野、公共性のセッター、又は方法を設定し、民間分野では、可変できるので、状態を変えずにインスタンスを新たに作成するパターンを示すことが分かった。
長い回答:まず、問題の不変性のみ適用される構造体やクラス分野はます。最も基本的な種類(番号、文字列、およびnullの場合)は、本質的に変更できるものがありますので(フィールド/プロパティの変更ます。5 5 5.操作の5つのみを返しまう不変です。
を作成でき変更可能な構造体などの System.Drawing.Point
.両 X
や Y
てセッターを変更するstructの分野:
Point p = new Point(0, 0);
p.X = 5;
// we modify the struct through property setter X
// still the same Point instance, but its state has changed
// it's property X is now 5
一部のように混乱immutablityというよりこの値型抜いてしまうことが確認された値(この名前)といいます。
void Main()
{
Point p1 = new Point(0, 0);
SetX(p1, 5);
Console.WriteLine(p1.ToString());
}
void SetX(Point p2, int value)
{
p2.X = value;
}
この場合に Console.WriteLine()
書き込みます"{X=0,Y=0}
".こちらの p1
したが変更されませんので SetX()
修正 p2
である コピー の p1
.こ p1
は 値型, なので 不変なので (い).
なぜ すべ 値型の可変?多くの理由...見 この質問.主にで変更可能な値型へのもあります。上記の例では、プログラマーが期待 p1
する (5, 0)
を呼び出した後 SetX()
.は想像選別による値。して分別収集なソートとして期待される。でも同じようなことがありますの辞書には、ハッシュ.の 素晴らしEric Lippert (ブログ)文 全シリーズの約不変性 したいと考えて、将来のC#. この一例 をまとめて見ることができる"変更"読み取り専用に変更します。
更新:自例:
this.readOnlyPoint.Offset(3, 4); // Is still (1, 2).
そのうLippertとメールアドレスを入力約の変更読み取り専用の変数. Offset(3,4)
が変更されたのは、 Point
, されるようになったが、 コピー の readOnlyPoint
, とはありませんでしたが割り当てるものです。
や その ではなぜ変更可能な値型の悪:いま 考え ご変更ものがあれば、実際に変更、コピー、予期せてしまいます。の場合 Point
した不変なので、 Offset()
思い返す新しい Point
, きなかったのではないかと思うので割り当て readOnlyPoint
.そしてま "ああ、この読み取り専用です。なぜ私を変えようとしているのですか?良いものをコンパイラの止まった。"
更新:お声を請求...思うんです。では、できる"考え"の構造体として 内部的に 不変なので、この変更は、structであることと同じで置き換え修正コピーします。することにもなる、CLRは内部メモリのためのすべて分かっています。成されると思うので結局どんぐフラッシュメモリです。編集できませんでバイトは、読み取りが必要になり全体のブロックをキロバイトのメモリへの変更をしたい書き込み、全体をブロックです。) しかし、まった"内部的に不変なので"は、実装の詳細(有料)で連絡しており、開発者とユーザーの構造体(またはインタフェースAPIの場合) ができ を変更します。できないので無視すること"を考えとして不変なので".
にコメントごと"できない場合もありますので参考に価値のフィールドまたは変数".想定するべてのstruct変数には、異なるコピー、修正一のコピーには影響しません。それは完全に真実ではありません。をもつことが知られている。は交換可能なら---
interface IFoo { DoStuff(); }
struct Foo : IFoo { /* ... */ }
IFoo otherFoo = new Foo();
IFoo foo = otherFoo;
foo.DoStuff(whatEverArgumentsYouLike); // line #1
foo = foo.DoStuff(whatEverArgumentsYouLike); // line #2
ライン#1、#2いても同様の結果...なぜですか?ので foo
や otherFoo
参照 同じ箱入りインスタンス のFoo.何が変更となります foo
沿#1反映さ otherFoo
.ライン#2に置き換え foo
新しい価値とは何も行いませんへ otherFoo
(仮 DoStuff()
新たに追加された仕様 IFoo
インスタンスでない変更 foo
ます!
Foo foo1 = new Foo(); // creates first instance
Foo foo2 = foo1; // create a copy (2nd instance)
IFoo foo3 = foo2; // no copy here! foo2 and foo3 refer to same instance
修正 foo1
な影響 foo2
または foo3
.修正 foo2
ログイン後に表示される foo3
, ていない foo1
.修正 foo3
ログイン後に表示される foo2
な foo1
.
混乱?こだわり不変の価値や種類に対する衝動の変更を行ったという。
更新:固定誤植に最初のサンプルコード
他のヒント
可変性と価値をタイプ別物だったというわけです。
を定義するタイプとしての価値型のランタイムコピーの代わりに、値の参考を行います。可変性には実装に依存し、各クラスを実装することについてお聞きしましょう。
できる構造体は可変ですがベストプラクティスを作る値型の不変です。
たDateTimeインスタンスは常に新しいインスタンスの場合だけ電源をオンにする"という動作します。点では変更可能な、変更できます。
にお答え:ない不変の定義によって違いますので、それぞれの場合すべき変更可能です。例えばあるべきであるオブジェクトは辞書のキーとして、不変です。
しかし理論などがあり、その すべての 種類は不変です。に変更する場合参照型は、こういう書くための新しいオブジェクトの同じ住所により変更あります。
やきと主張するものではあり変更可能な他の言語であるメモリされていたひとつにまで上書きされます。
十分な抽象化を無視十分な言語機能しているのも特徴的なので、結論ます。
そのミスをしたら教えて下さい。じます。純仕様、価格の種類は可変です。に変更することができます。.
int i = 0;
Console.WriteLine(i); // will print 0, so here, i is 0
++i;
Console.WriteLine(i); // will print 1, so here, i is 1
もみ重ねの上に成り立っていた.変数 i
みを宣言します。もうのでこの宣言である。
何かのように機能言語の変更不能な変数は、このような法律に基づいて行われる。の++いすることはできません。一変数の宣言されたので、固定の値です。
ます。純ですが、実はそうではありませんの場合、あ停からの修正の i
後で宣言しています。
考えてみるとか、他の例は多めの方が良いでしょう:
struct S {
public S(int i) { this.i = i == 43 ? 0 : i; }
private int i;
public void set(int i) {
Console.WriteLine("Hello World");
this.i = i;
}
}
void Foo {
var s = new S(42); // Create an instance of S, internally storing the value 42
s.set(43); // What happens here?
}
最終ラインにより、ロジック、そして実際に新しいオブジェクトは、上書きの一つとなければならないかを指します。でも、それだけではありません。を構築する新しいオブジェクトは、コンパイラの設定を i
変数42.ものです。でみを通じてアクセス可能なユーザ定義のコンストラクタを明示的に士の値43(設定値が0ではなく、それを通じて set
方法は、起きます。のコンパイラがない方 だけで 新しいオブジェクトを作成の価値観できました。を s.i
設定できます43は 修正 現在のオブジェクトを呼び出し set()
.のコンパイラではなくなることで、変化の挙動のプログラムでの印刷、コンソール)
そのためのすべての構造体への不変なので、コンパイラがチや休憩に規定されたものの翻訳であります。もちろんいいのルールを証明することはできます。いることによってすべての整数が等しいやり過ぎることを定めるためのクラスがコンピュータまっている。し滞在のルールの言語の構造体は可変です。
ならないようにしたい複雑な推論 この検討
ref
パラメータとボクシング.自覚しています そのp = p.Offset(3, 4);
表現 不変性のほうが良いp.Offset(3, 4);
います。その 問題がない値の種類 不変な定義?
それではまだ営業は、お使いいただけます。実際の傾向値型のコピーをすることは、自らの移動と機能メッシュも不変のものはありませんが実際に変更できないとして不変なので、ご指摘のとおり、利用できる参照ください。
な値型の不変な定義?
なにはなりません:を見れば System.Drawing.Point
struct例えば、セッターなどのゲッターその X
物件です。
しかしこのようなすべての値の種類 すべ 定義変更不能なApiを用意しています。
と思い、混乱すると、参照型であるように値の型でしなければならないので不変です。の主な違いについ値型と参照型には変化を通じて、参照型でのその他の名前です。そのようなことはな価値の種類
public class foo
{
public int x;
}
public struct bar
{
public int x;
}
public class MyClass
{
public static void Main()
{
foo a = new foo();
bar b = new bar();
a.x = 1;
b.x = 1;
foo a2 = a;
bar b2 = b;
a.x = 2;
b.x = 2;
Console.WriteLine( "a2.x == {0}", a2.x);
Console.WriteLine( "b2.x == {0}", b2.x);
}
}
生産:
a2.x == 2
b2.x == 1
さあ、っていうの価値は意味がないんですが値型-その他なんでも保管が必要なのでもうべきと考える不変性のデザイン。とを不変のref型、更に既存の基準の生産の新しいオブジェクトではなく、既存の一つで、値型の挙動とな価値だけ有化させることその他の名前です。
もちろん、システム。Stringクラスはどのように見えます。
昨年に書いたブログをポストに関する問題を走行できるな構造体 変更できません。
こどもので決思っていたが、あるきっかけで
//Struct declaration:
struct MyStruct
{
public int Value = 0;
public void Update(int i) { Value = i; }
}
サンプルコード:
MyStruct[] list = new MyStruct[5];
for (int i=0;i<5;i++)
Console.Write(list[i].Value + " ");
Console.WriteLine();
for (int i=0;i<5;i++)
list[i].Update(i+1);
for (int i=0;i<5;i++)
Console.Write(list[i].Value + " ");
Console.WriteLine();
このコード:
0 0 0 0 0
1 2 3 4 5
現していきましょう同じですが、代替の配列汎用 List<>
:
List<MyStruct> list = new List<MyStruct>(new MyStruct[5]);
for (int i=0;i<5;i++)
Console.Write(list[i].Value + " ");
Console.WriteLine();
for (int i=0;i<5;i++)
list[i].Update(i+1);
for (int i=0;i<5;i++)
Console.Write(list[i].Value + " ");
Console.WriteLine();
の出力です:
0 0 0 0 0
0 0 0 0 0
の説明は非常に簡単です。かせないボクシング/unboxing...
アクセス時に要素の配列から、ランタイムの配列要素を直接、Update()メソッドの配列。この構造体の配列を更新しました。
第二の例では、使用していました汎用 List<>
.どのようなときにアクセスしたときに特定の要素かどうかが判別されます。ものindexer性と呼ばれるメソッドになっています。値の種類は、常にコピーが返される方法であり、このよう正確に何が起こる:リストのindexer方法を取得しますが、構造体内部配列を返しますそして、呼び出し側に返します。での懸念が値型をコピーするとともに、Update()メソッドが呼ばれますのでコピーするのに対しては何の影響もありませんリスト独自の項目です。
つまり、必ずご構造体は不変ですが、な時に必ずコピーします。ほとんどの時間では明らかであり、かなどに利用できる可能性があるときに本当に驚きます---
います。例:
Point p = new Point (3,4);
Point p2 = p;
p.moveTo (5,7);
この例では moveTo()
は 場所 動作します。この変化の構造を隠後の参照 p
.できるよう p2
:での位置も変化しています。変更不能な構造 moveTo()
思い返す新しい構造:
p = p.moveTo (5,7);
現在、 Point
は変更不可能なので、ときに参考にして繰り返して行なうことができるが、いず驚くことで生きています。見てみましょう i
:
int i = 5;
int j = i;
i = 1;
ここは違います。 i
は不変なので、 5
です。第二の課題なコピーへの参照を保持する構造を含有する i
でコピーするコンテンツの i
.その舞台裏で何か違う:きの完全なコピーで可変するだけでなくコピーのアドレスのメモリを参照)。
同等のオブジェクトのコピーコンストラクタ:
Point p = new Point (3,4);
Point p2 = new Point (p);
ここではの内部構造 p
コピーを新しいオブジェクトまたは構造 p2
が含まれまでの参考にします。しかし、これはかなり高額な運用とは異なり、整数割以上)をほとんどのプログラミング言語を区別する
としてコンピューターなしの強力を得ており、メモリ、この区別がなくなりが原因となる膨大なバグや問題をもたらしていま次世代は変更不能なオブジェは、操作により保護されることの取引も int
正吹きオブジェクトです。のように、カナダ、中国、インドでの大きな一歩前進プログラムの安定が悲しみ、最初の数年間でよく高信頼ソフトウェアです。今日、コンピュータだけでな速度です。
いいえ、値の種類 ない 変更不能による定義で設定します。
最初に、なるべての質問"い値の種類と同様に動作不変なのですか?"うであれば変更できっこよく混乱した。
struct MutableStruct
{
private int state;
public MutableStruct(int state) { this.state = state; }
public void ChangeState() { this.state++; }
}
struct ImmutableStruct
{
private readonly int state;
public MutableStruct(int state) { this.state = state; }
public ImmutableStruct ChangeState()
{
return new ImmutableStruct(this.state + 1);
}
}
[現在も継続中です。]
を定義するか否かのタイプに変更可能なまたは不変なので、なければな定義される"タイプ"を参照します。時保管場所の参照型で宣言され、宣言は単に割り当てスペースの参照を保持するオブジェクト格納され、他の場所では達成この宣言を生じさせるものではありません、実際のオブジェクト。しかし、コンテキストが一つの特定の基準種類いのではないについてのお話をしていただき、 保存場所を参照, く のオブジェクトを特定するを参照する.この一から書き込みを行うことができま保管場所を持つオブジェクトに対する参照を意味のないことをこのオブジェクト自体は可変です。
この場合、保管場所の値の型が宣言されると、システムは配分以内に参考として示したもので、これらの場所の入れ子貯蔵場所ごとの公私の分野で開催される値のタイプです。すべてのサンディエゴの値の型が開催される保管場所です。合を定義する変数 foo
タイプ Point
その二つの分野 X
や Y
, 保3-6。合を定義するインスタンスの Point
に foo
としての対 分野, は、インスタンス変更可能な場合にだけ、その foo
は可変です。が定義のインスタンス Point
としての 価値観 開催は,これらの分野における例"3、6mm")、そのインスタンスは不変なので、以来、変化の分野が Point
に異なるインスタンス.
だと思っていく考えであり、価値の型のインスタンスの分野ではなく、価値観となっている。その定義は、値型の保存に変更可能な保管場所、非デフォルト値が存在しま 常に すると変更可能なので宣言しています。決 MyPoint = new Point(5,8)
の新しいインスタンスを構築しま Point
, で、分野を X=5
や Y=8
, その突然変異 MyPoint
置換値の分野において、新たに作成された Point
.場合でも、structの無い変更する方法その分野外のコンストラクタがなstructタイプを守ることができ、インスタンスからすべての分野で上書きされるコンテンツのインスタンス.
ちなみに、簡単な例が変更可能な構造体を実現できる意味は達成可能なその他の方法:仮に myPoints[]
ある単一要素の配列であるアクセスについては、アクセス権を複数のスレッド、二のスレッドを同時に実行コード:
Threading.Interlocked.Increment(myPoints[0].X);
の場合 myPoints[0].X
から始まりゼロに等しいか否かを問わず、別紙特別スレッドを上記のコードから同時に、 myPoints[0].X
以下。また試みを模倣し、上記のコード:
myPoints[0] = new Point(myPoints[0].X + 1, myPoints[0].Y);
その場合、任意のスレッドを読み myPoints[0].X
時間別のスレッドで読み込みと書きの改正価値は、結果の値が失われてしまうの結果と myPoints[0].X
が任意に終わる任意の値の間の1-20とします。
オブジェ/構造体は不変でき渡された関数などのデータの変更はできません、返された構造体である new
struct.クラシックの例は
String s = "abc";
s.toLower();
の場合 toLower
機能はその新しい文字列が返却されること置き換え"s"で変更でき、その機能が字を置き換えの手紙の内"s"はい"を宣言す新しい文字列"で可変です。