不変とはどういう意味ですか?


103

文字列が不変である場合、それはそれが意味することを意味しますか?...(JavaScriptと仮定しましょう)

var str = 'foo';

alert(str.substr(1)); // oo

alert(str); // foo

文字列のメソッドを呼び出すと、変更された文字列が返されますが、最初の文字列は変更されません。

文字列が変更可能だった場合、2番目も同様にalert()返さooれるということですか?

回答:


104

つまり、オブジェクトをインスタンス化すると、そのプロパティを変更できなくなります。最初のアラートでは、fooを変更していません。新しい文字列を作成しています。これが、2番目のアラートでooではなく「foo」と表示される理由です。

文字列のメソッドを呼び出すと、変更された文字列が返されますが、最初の文字列は変更されません。

はい。いったん作成された文字列を変更することはできません。これは、新しい文字列オブジェクトをstr変数に割り当てることができないという意味ではありません。strが参照する現在のオブジェクトを変更することはできません。

文字列が変更可能だった場合、それは2番目のalert()がooも返すことを意味しますか?

技術的には、サブストリングメソッドは新しいストリングを返すため、違います。オブジェクトを変更可能にしても、メソッドは変更されません。変更可能にすることは、技術的には、部分文字列が新しい文字列を作成する代わりに元の文字列を変更するように作成できることを意味します。


同じ文字列を変更して割り当てた場合、文字列var str = 'foo'が更新されます。str = str.substr(1)); // oo alert(str); // oo
Ashwin G

以下のコードはどうですか?文字列値が変更されます。var name = "Santosh"; console.log(name.substr(0,2)); var name = "kumar" console.log(name); いかに不変なのか
Santosh

97

下位レベルでは、不変性は、文字列が格納されているメモリが変更されないことを意味します。文字列を作成すると"foo"、値を格納するためのメモリが割り当てられます"foo"。このメモリは変更されません。たとえばで文字列を変更すると、substr(1)新しい文字列が作成され、を格納するメモリの別の部分が割り当てられ"oo"ます。これで、2つの文字列がメモリに"foo"あり"oo"ます。使用し"foo"なくなったとしても、ガベージコレクションが行われるまで残ります。

文字列操作が比較的高価な理由の1つ。


1
数値も不変です。
RNクシュワハ2015年

3
2015年こんにちは!「下位レベルでは、不変性とは、文字列が格納されているメモリが変更されないことを意味します。」---これは制限が厳しく、正しく聞こえません。不変性はユーザーランドのみに関するものであり、言語仕様の不変条件が維持されるとすぐに、メモリアロケータが好きなときに仮想メモリが変更される可能性があります。
zerkms 2015

2
この答えは、容認された答えよりも論理的です。
Ejaz Karim 2016

しかし、私はvar str = 'foo'のようにすることができます。str = 'bar'で変更できます。str値はこのように変更されましたか?
ハッカー

@ハッカーいや。メモリ内の新しい場所を指す変数に新しい文字列を割り当てました。
だます

13

不変とは、変更または修正できないことを意味します。

したがって、文字列に値を割り当てると、この値は置き換えられるのではなく、最初から作成されます。したがって、新しい文字列が同じ文字列に割り当てられるたびに、コピーが作成されます。したがって、実際には、元の値を変更することはありません。


9

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

上記では、lit1lit2は同じ文字列リテラルを使用して構築されているため、同じメモリアドレスを指しています。lit1 == lit2結果trueはになります。これらはまったく同じオブジェクトだからです。

ただし、consクラスコンストラクターを使用して構築されます。パラメータは、同じ文字列定数ではあるが、新しいメモリのコンストラクタ割り当てはcons、意味はcons同じオブジェクトではありませんlit1し、lit2同じデータを含むにもかかわらず、。

もちろん、3つの文字列にはすべて同じ文字データが含まれているため、このequalsメソッドを使用するとtrueが返されます。

(もちろん、どちらのタイプの文字列構成も不変です)


3

不変とは、値を変更できないことを意味します。作成された文字列オブジェクトは、不変であるため変更できません。文字列の部分文字列を要求すると、要求された部分を持つ新しい文字列が作成されます。

文字列の操作中にStringBufferを使用すると、代わりに操作がより効率的になります。StringBufferは文字配列を文字配列に格納し、文字配列の容量と配列の長さを保持する変数を格納します(文字配列形式の文字列)


3

可変性の教科書定義は、責任を負うものであり、変更または変更されることがあります。プログラミングでは、時間とともに状態が変化することが許可されているオブジェクトを意味する言葉を使用します。不変の値は正反対です。作成後は変更できません。

これが奇妙に思われる場合は、私たちがいつも使用している値の多くが実際には不変であることを思い出させてください。

var statement = "I am an immutable value";
var otherStr = statement.slice(8, 17);

私は、2行目がステートメントの文字列を決して変更しないことを知って驚く人はいないと思います。実際、操作する文字列を変更する文字列メソッドはなく、すべて新しい文字列を返します。その理由は、文字列は不変であるためです。文字列は変更できません。新しい文字列しか作成できません。

JavaScriptに組み込まれる不変の値は文字列だけではありません。数値も不変です。2 + 3という式を評価すると、数値2の意味が変わる環境を想像できますか?ばかげたことに聞こえるかもしれませんが、オブジェクトと配列を常に使用しています。


2

文字列からスタックへ... Eric Lippertのブログから取られた、わかりやすい例:

C#3.0のA *を使用したパス検索、パート2 ...

System.Collections.Generic.Stackのような変更可能なスタックは明らかに適切ではありません。既存のパスを取得して、最後の要素のすべての隣接要素に対して新しいパスを作成できるようにしたいのですが、新しいノードを標準スタックにプッシュすると、スタックが変更されます。プッシュする前にスタックのコピーを作成する必要があります。これは、その内容のすべてを不必要に複製することになるため、ばかげています。

不変スタックにはこの問題はありません。不変スタックをプッシュすると、テールとして古いスタックにリンクする新しいスタックが作成されるだけです。スタックは不変なので、他のコードが一緒になってテールの内容をいじる危険はありません。古いスタックを心ゆくまで使い続けることができます。

不変性の理解を深めるには、この記事から始まるEricの投稿を読んでください。

C#の不変性パート1:不変性の種類


その引用には奇妙な主張が含まれています-そのスタックデータ構造(実際にはテール共有を備えた複数のスタック)は全体として可変構造です-すべてのプッシュまたはポップは構造を変更します。個々のアイテムのみが不変です。そして原則として、同じ構造を持つことができますが、要素は変更可能です。これは、元に戻せるunion-find IIRCのいくつかのバリエーションで発生します。不変性には大きな利点がありますが、ミュータブルを使用すると、最適化としてデータ構造の一部またはすべてを共有することが完全に可能です。他の参照に対して明白な不変性が必要な場合でも、必要に応じていつでもコピーオンライトが可能です。
Steve314、2007

0

この概念を理解する1つの方法は、JavaScriptがすべてのオブジェクトをどのように処理するかを参照することです。これは参照です。すべてのオブジェクトがインスタンス化された後は変更可能であることを意味します。つまり、新しいメソッドとプロパティを持つオブジェクトを追加できます。オブジェクトを不変にしたい場合、オブジェクトはインスタンス化された後は変更できないため、これは重要です。

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