文字列が不変である場合、それはそれを意味します...(JavaScriptを想定しましょう)
_var str = 'foo';
alert(str.substr(1)); // oo
alert(str); // foo
_
文字列のメソッドを呼び出すと、変更された文字列を返しますが、最初の文字列は変更されませんか?
文字列が変更可能な場合、2番目のalert()
もoo
を返すことを意味しますか?
これは、オブジェクトをインスタンス化すると、そのプロパティを変更できないことを意味します。最初のアラートでは、fooを変更していません。新しい文字列を作成しています。これが、2番目のアラートでooではなく「foo」と表示される理由です。
文字列のメソッドを呼び出すと、変更された文字列を返しますが、最初の文字列は変更されませんか?
はい。作成された文字列を変更することはできません。これは、新しい文字列オブジェクトをstr
変数に割り当てることができないという意味ではありません。 strが参照する現在のオブジェクトを変更することはできません。
文字列が変更可能な場合、2番目のalert()もooを返すことを意味しますか?
技術的には、サブストリングメソッドが新しいストリングを返すため、いいえ。オブジェクトを可変にしても、メソッドは変更されません。可変にするということは、技術的には、サブストリングが新しいストリングを作成する代わりに元のストリングを変更するように作成できることを意味します。
下位レベルでは、不変性とは、文字列が保存されているメモリが変更されないことを意味します。文字列_"foo"
_を作成すると、値_"foo"
_を保存するためのメモリが割り当てられます。このメモリは変更されません。たとえば、substr(1)
で文字列を変更すると、新しい文字列が作成され、_"oo"
_を格納するメモリの別の部分が割り当てられます。これで、メモリ内に_"foo"
_と_"oo"
_の2つの文字列ができました。 _"foo"
_をもう使用しない場合でも、ガベージコレクションが行われるまで保持されます。
文字列操作が比較的高価な理由の1つ。
不変とは、変更または変更できないことを意味します。
したがって、文字列に値を割り当てると、この値は置き換えられるのではなく、ゼロから作成されます。したがって、同じ文字列に新しい値が割り当てられるたびに、コピーが作成されます。したがって、実際には、元の値を変更することはありません。
JavaScriptについては確信がありませんが、Javaでは、文字列は「文字列定数プール」によって不変性への追加のステップを踏みます。文字列は、文字列リテラル("foo"
)またはString
クラスコンストラクターで構築できます。文字列リテラルで構築された文字列は文字列定数プールの一部であり、同じ文字列リテラルは常にプールの同じメモリアドレスになります。
例:
String lit1 = "foo";
String lit2 = "foo";
String cons = new String("foo");
System.out.println(lit1 == lit2); // true
System.out.println(lit1 == cons); // false
System.out.println(lit1.equals(cons)); // true
上記では、lit1
とlit2
の両方が同じ文字列リテラルを使用して構成されているため、同じメモリアドレスを指しています。 lit1 == lit2
は、まったく同じオブジェクトであるため、true
になります。
ただし、cons
はクラスコンストラクターを使用して構築されます。パラメータは同じ文字列定数ですが、コンストラクタはcons
に新しいメモリを割り当てます。つまり、cons
はlit1
およびlit2
と同じオブジェクトではなく、同じデータ。
もちろん、3つの文字列にはすべて同じ文字データが含まれているため、equals
メソッドを使用するとtrueが返されます。
(もちろん、両方のタイプの文字列構築は不変です)
不変は、値を変更できないことを意味します。作成された文字列オブジェクトは、不変として変更できません。文字列の部分文字列を要求すると、要求された部分を持つ新しい文字列が作成されます。
文字列の操作中にStringBufferを使用すると、文字配列の容量と配列の長さ(char配列形式の文字列)を保持する変数を含む文字配列にStringBufferが格納されるため、操作がより効率的になります
可変性の教科書の定義は、責任を負うか、変更または変更の対象となります。プログラミングでは、Wordを使用して、状態が時間とともに変化するオブジェクトを意味します。不変の値は正反対です。作成された後は変更できません。
これが奇妙に思える場合、私たちが常に使用する値の多くは実際には不変であることを思い出させてください。
var statement = "I am an immutable value";
var otherStr = statement.slice(8, 17);
2行目がステートメントの文字列を変更しないことを知って誰も驚かないと思います。実際、操作する文字列を変更する文字列メソッドはなく、すべて新しい文字列を返します。理由は、文字列は不変であるためです。変更することはできず、新しい文字列を作成することしかできません。
JavaScriptに組み込まれている不変の値は文字列だけではありません。数字も不変です。式2 + 3を評価すると数値2の意味が変わる環境を想像できますか?それは馬鹿げているように聞こえますが、私たちは常にオブジェクトと配列でこれを行っています。
文字列からスタックまで... Eric Lippertのブログ から取ったわかりやすい例
System.Collections.Generic.Stackのような可変スタックは明らかに適切ではありません。既存のパスを取得し、その最後の要素のすべてのネイバーに対して新しいパスを作成できるようにしたいのですが、新しいノードを標準スタックにプッシュするとスタックが変更されます。スタックをプッシュする前にスタックのコピーを作成する必要がありますが、これはすべての内容を不必要に複製するため、愚かなことです。
不変スタックにはこの問題はありません。不変のスタックにプッシュしても、古いスタックにリンクする新しいスタックが作成されるだけです。スタックは不変なので、他のコードが来てテールの内容をいじる危険はありません。古いスタックを思いのままに使い続けることができます。
不変性の理解を深めるには、これから始まるEricの投稿を読んでください。
この概念を理解する1つの方法は、javascriptがすべてのオブジェクトをどのように扱うかを調べることです。これは参照によるものです。すべてのオブジェクトがmutableであるということは、インスタンス化された後、つまり、新しいメソッドとプロパティを持つオブジェクトを追加できることを意味します。オブジェクトを不変にしたい場合、オブジェクトはインスタンス化された後は変更できないため、これは重要です。