不変性を回避する


13

私はオブジェクト指向プログラミングに慣れていないので、把握に時間がかかっている概念の1つは不変性です。昨夜電球が消えたと思うが、確認したい:

不変オブジェクトを変更できないというステートメントに出くわすと、たとえば次のようなことができるため困惑します。

NSString *myName = @"Bob";
myName = @"Mike";

そこで、不変型NSStringのmyNameを変更しました。私の問題は、「オブジェクト」という言葉がメモリ内の物理オブジェクト、または抽象化「myName」を指すことがあるということです。前者の定義は、不変性の概念に適用されます。

変数については、不変性のより明確な(私にとって)定義は、不変オブジェクトのは、メモリ内の位置、つまり参照(ポインタとも呼ばれる)を変更することによってのみ変更できるということです。

これは正しいですか、それとも私はまだ森の中で迷っていますか?


13
あなたのあなたのタイプではありませんNSString、それは「へのポインタNSString不変ではありません」、。私は客観的Cの何も知らないが、私はあなたの例では推測している@"Mike"の新しいインスタンスを作成しているNSStringし、それを割り当てるのポインタmyName。したがってmyName、指していたオブジェクトは変更せず、指し示していたものだけを変更しました。
fwgx

2
@fwgxそれを答えにすると、あなたは私の賛成を得ます。
グルシャン

すべての返信をありがとうございました、彼らは非常に有用です。今、不変オブジェクトはメモリ内の値であり、それを指す変数ではないことを理解しています。
マイケルマンゴールド

@Gulshan完了、以下を参照してください
。...-fwgx

不変性を理解するには、バインディング(つまり、オブジェクトに名前を付ける)と可変性(つまり、名前を別のオブジェクトに再割り当てできる)を明確に分離するプログラミング言語を学ぶことをお勧めします。ML(どんな装いでも:SML、Ocaml、F#)は良い例です。
ジル 'SO-悪であるのをやめる'

回答:


4

あなたは正しい方向に向かっているように聞こえますが、まだ十分に理解できていません。これは間違っています:

そこで、不変型NSStringのmyNameを変更しました。私の問題は、「オブジェクト」という言葉がメモリ内の物理オブジェクト、または抽象化「myName」を指すことがあるということです。

コードスニペットでmyNameは、は不変型ではなくNSString可変NSString*(NSStringへのポインター)です。あなたが不足している重要なことはことを理解することがあるように聞こえるポインタがちょうど別の値であり、そしてそれが指すものとは完全に別の人生がある(あなたがその生涯を通じて、それを途中で変更した場合、または物事を)。

あなたは言う:

...不変オブジェクトの値は、メモリ内の位置、つまり参照(ポインタとも呼ばれる)を変更することによってのみ変更できます。

これは間違っています。オブジェクトは、それを指すポインターを所有していません。また、オブジェクトのメモリー位置は、そのポインターによる制御や影響を受けません。

したがって、NSString例の2つのオブジェクト(@"Bob"および@"Mike")は、myName変数とは完全に分離されています。また、互いに完全に分離されています。あなたが変更した場合myNameにポイントを@"Mike"指しするのではなく@"Bob"、あなたが変更されていないNSStringオブジェクトを。


完全を期すために、ポインターの変更が指すオブジェクトに影響を与える可能性があるという点で、ガベージコレクターはこれをより複雑にすることに注意してください。ただし、これはコードの観察可能な動作に影響を与えない実装の詳細です。


17

あなたは言葉で失われます。不変性とは、変数を変更しない限り、他の変数で何をしても、常に同じ値が「含まれる」ことを意味します。

Cの反例(それを許可するアーキテクチャを想定して、少し簡略化):

 char *a = "Hello World";
 char *b = a;
 b[0] = 'Y';

これで、文字列「Hello World」が「含まれる」(つまり指す)ことはなくなりましたが、代わりに「Yello World」になります。

Javaや(EDIT:safe)C#などの文字列が不変の言語では、それを行うことはできません。ありえない。これは、プログラムのすべての部分が文字列への参照を安全に保持し、その内容が決して変わらないことを信頼できることを意味します。そうでなければ、安全のためにコピーを作成する必要があります。

しかし、変数はまだ変更可能です。別のオブジェクトを指すようにすることができます。それは、オブジェクト自体が背中の後ろで変化しないということだけです。


1
技術的に C#で文字列の内容を変更できunsafeます。コードを使用するだけです。
アーロンノート

1
Aaronaught:情報をありがとう、あなたは正しい。:どのように知っておく必要があるすべての人のためのmsdn.microsoft.com/en-us/library/ms228599.aspx
user281377

10

変数をオブジェクトと混同しています。オブジェクトへの参照を格納するために変数を使用できますが、それらはオブジェクトではありません。オブジェクトは変数ではなく不変であるため、変数をあるオブジェクトから別のオブジェクトに変更することはできますが、オブジェクトが不変である場合はそのオブジェクトの属性を変更することはできません。

オブジェクトを騒々しく酔っ払った隣人と考えてください。彼が理にかなっている(可変)場合、あなたは彼のドアをノックして、彼がそれほど騒ぎのないライフスタイルに彼を変えることができるかもしれません。しかし、彼が不変である場合、あなたの唯一の変更は、他の誰かが入ることを願うことです!


3
ミュートしたい隣人がいました。
デイブいや

説明が十分であるため、2番目の段落の例を必要とは思わない。IMOの例は混乱させる可能性があります。ただし、チャップの質問に対する簡潔な回答の場合は+1。
ポールマッケイブ

@DaveNay:ステルスのしゃれをおaびします。まったく意図していませんでした。
キリアンフォス

6

変数はオブジェクトではありません。変数は名前であり、オブジェクト(またはより一般的には値)を参照します。

たとえば、「ゴールキーパー」とは、ゴールを守る責任のあるオブジェクト(人)を指すために使用する名前です。しかし、その人を別の人に置き換えると(前者が負傷したなどの理由で)、新しい人は「ゴールキーパー」と呼ばれます。

代入ステートメントは変数を可変にするものです(Haskellなどの一部の言語には変数がなく、実際に不変変数を使用します)。名前の意味を再定義して、値を再割り当てできます。

オブジェクト自体不変になりました。数千年前には、ダイヤモンドは不変であると考えられていました。ダイヤモンドで何をしたとしても、修正することはできません。ワガウオガと呼ばれても(「私たちの部族の最大の光沢のある石」にゆるやかに変換される)、またはそのように呼ぶのをやめても(より大きなものを見つけたため)、ダイヤモンドは同じままでした。対照的に、ワガウガで面白い写真を彫るのに使用していた木片は同じままではありませんでした。可変であることが証明されました。たとえ同じ名前だったとしても。

変数と値は両方とも不変(独立)にすることができます。この場合、不変なのはオブジェクトです。を作成するとNSString、変更できません。名前を付けて渡すことができますが、同じままです。それとは対照的に、NSMutableStringたとえばsetStringメソッドを呼び出すことにより、作成後に変更できます。


waggawooga比較が大好き!
マイケルK

必要以上に元のポスターを混同しないように:変数はオブジェクトではないという点は良いことですが、変数は実際には「値を参照する名前」として定義されていません。変数には名前が付けられている場合あり、値を含むストレージの場所を指します。多くのプログラミング言語では、変数に名前を付ける必要はありません。多くの言語では、同じ変数に複数の名前を付けることができます。
エリックリッパー

4

オブジェクト自体と、そのオブジェクトにバインドされた変数名という2つの概念が混在しているため、あなたは道に迷ったと思う。

不変オブジェクトは変更できません。限目。ただし、不変オブジェクトにバインドされた変数名(シンボル)は、別の不変オブジェクトにバインドされるように変更できます。

つまり、これら2行で行ったことは次のとおりです。

  1. 値が「Bob」の不変文字列オブジェクトを作成します
  2. myNameそのオブジェクトにシンボルをバインドします
  3. 値「Mike」で不変の文字列オブジェクトを作成します
  4. myNameそのオブジェクトにシンボルをバインドします

2

あなたのあなたのタイプではありませんNSString、それは「へのポインタNSString不変ではありません」、。客観的なCについては何も知りませんが、あなたの例で@"Mike"は、の新しいインスタンスを作成し、NSStringそれをポインターに 割り当てていると推測していますmyName。あなたは、オブジェクトに変更されていないようmyNameして指しだけに、どのようなそれが指していたが。


0

変更可能なオブジェクトの例を次に示しますchar。Cの配列:

char str[10];

私が変更できる内容のをstr(限り、それは10文字以下だと)私の心の内容に。C文字列ライブラリ関数によって文字列として認識されるためには、末尾に0が必要であるため、最大9文字の文字列を保持できます。

strcpy(str, "hello"); // str now contains the string "hello\0"
strcpy(str, "world"); // str now contains the string "world\0"

str[0] = 'W';         // str now contains "World\0"

ウント・ソ・ワイター

これをJavaの文字列オブジェクトと比較してください。

String foo = "Hello";

文字列インスタンス(文字 'H'、 'e'、 'l'、 'l'、および 'o'を含むメモリのチャンク)は変更できません。その文字列の内容を変更することはできません。あなたが何かを書くとき

foo = foo + " World";

「Hello」インスタンスの最後に「World」を追加していません。新しいインスタンスを作成し、それに「Hello World」をコピーfooし、その新しい文字列インスタンスを参照するように更新しています。

foo文字列インスタンス自体は含まれません。それはそのインスタンスを参照するだけであり(CまたはObj-Cのポインターに似ています)、したがって、Stringのような型が参照型と呼ばれる理由です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.