web-dev-qa-db-ja.com

多くのプログラミング言語で文字列が不変なのはなぜですか?

可能性のある複製:
Javaおよび.NETで文字列を変更できないのはなぜですか?
。NET文字列が不変な理由

C#、Java、Pythonなど、いくつかの言語がこれを選択しています。メモリの節約やcompareなどの操作の効率を上げることを目的としている場合、連結やその他の変更操作にどのような影響がありますか?

60
snowfox

不変タイプは一般的に良いことです:

  • 同時実行性が向上します(変更できないものをロックする必要はありません)。
  • エラーを減らします。可変オブジェクトは、予期しないときに変更されやすく、さまざまな奇妙なバグ(「遠くでのアクション」)が発生する可能性があります。
  • それらは安全に共有できます(つまり、同じオブジェクトへの複数の参照)。これにより、メモリの消費を削減し、キャッシュの使用率を向上させることができます。
  • 共有すると、コピーが非常に安価になりますO(1)操作が可能な場合O(n)変更可能なオブジェクトの防御コピーをとる必要がある場合。コピーは非常に一般的な操作であるため、これは非常に重要です(たとえば、パラメーターを渡したいときはいつでも...)。

その結果、文字列を不変にするのはかなり合理的な言語設計の選択です。

一部の言語(特にHaskellやClojureなどの関数型言語)はさらに進化し、ほとんどすべてを不変にしています。この 啓発的なビデオ は、不変性の利点に興味がある場合、一見の価値があります。

不変の型には、いくつかのマイナーな欠点があります。

  • 連結などの変更された文字列を作成する操作は、新しいオブジェクトを作成する必要があるため、コストが高くなります。 ロープ 。さらに、本当に効率的に文字列を連結する必要がある場合は、Java StringBuilder などの特別なツールをいつでも使用できます。
  • 大きな文字列に小さな変更を加えると、大きな文字列の完全に新しいコピーを作成する必要が生じる可能性があり、明らかにメモリ消費が増加します。ただし、古いコピーは参照を維持しないとガベージコレクションがすぐに行われるため、ガベージコレクションされた言語では通常、これは大きな問題ではないことに注意してください。

ただし、全体として、不変性の利点は、マイナーな欠点をはるかに上回ります。パフォーマンスのみに関心がある場合でも、並行処理の利点とコピーの安さにより、一般に、不変文字列はロックと防御コピーを備えた可変文字列よりもはるかにパフォーマンスが高くなります。

73
mikera

これは主にプログラミングエラーを防ぐためのものです。たとえば、文字列はハッシュテーブルのキーとして頻繁に使用されます。変更できると、ハッシュテーブルが破損します。これは、使用中にデータの一部が変更されると問題が発生する例の1つにすぎません。セキュリティはもう1つです。ユーザーが要求した操作を実行する前に、特定のパスにあるファイルへのアクセスがユーザーに許可されているかどうかを確認する場合、パスを含む文字列は変更できないほうがいいです...

マルチスレッディングを行う場合はさらに重要になります。不変データはスレッド間で安全にやり取りできますが、可変データは無限の頭痛の種です。

基本的に、不変データは、その上で動作するコードを推論しやすくします。これが、純粋に関数型の言語がすべてを不変にしようとする理由です。

16

Java In Stringだけでなく、すべてのプリミティブWrapperクラス(Integer、Double、Characterなど)は不変です。正確な理由はわかりませんが、これらはすべての基本的なデータ型であると思いますプログラミングスキームは機能します。それらが変更されると、状況が乱れる可能性があります。具体的には、例として、リモートホストへのソケット接続を開いたとします。ホスト名は文字列、ポートは整数になります。 。接続の確立後にこれらの値が変更された場合はどうなりますか?.

パフォーマンスに関する限り、Javaは、スタックまたはヒープからではなく、リテラルプールと呼ばれる個別のメモリセクションからこれらのクラスにメモリを割り当てます。リテラルプールはインデックスが付けられており、文字列を使用する場合 "文字列 "を2回使用すると、リテラルプールの同じオブジェクトを指します。

3
Ameya

文字列を不変にすると、以前に作成した文字列のプールから同じ/類似の文字列を簡単に利用できるため、新しい文字列を簡単に参照できます。これにより、新しいオブジェクトの作成コストを削減できます。

0
saurabytes