[解決済み] .NETのStringはなぜimmutableなのか?[重複あり]
質問
周知のとおりです。 文字列 はイミュータブルです。Stringがimmutableである理由、そして ストリングビルダー クラスはミュータブルですか?
どのように解決するのですか?
- 不変型のインスタンスは本質的にスレッドセーフです。どのスレッドもそれを変更できないので、あるスレッドが他のスレッドと干渉する形でそれを変更するリスクは取り除かれます(参照自体は別の問題です)。
- 同様に、エイリアシングでは変更ができないため(xとyの両方が同じオブジェクトを参照している場合、xの変更はyの変更を伴う)、コンパイラの最適化がかなり可能になっています。
- また、メモリを節約する最適化も可能です。インターナルやアトマイジングが最もわかりやすい例ですが、同じ原理の他のバージョンも可能です。私は以前、不変オブジェクトを比較し、重複する参照を置き換えて、すべて同じインスタンスを指すようにすることで、約半GBのメモリ節約を実現しました(時間はかかりますが、大量のメモリを節約するための1分間の追加起動は、問題のケースにおいてパフォーマンスの勝利となりました)。ミュータブルオブジェクトの場合、それはできません。
-
でない限り、メソッドとして不変の型をパラメータに渡しても、副作用は生じない。
out
またはref
(これはオブジェクトではなく参照を変更するため)。したがって、プログラマは、もしstring x = "abc"
をメソッドの最初に書いて、それがメソッド本体で変化しないのであればx == "abc"
をメソッド終了時に指定します。 -
概念的には、セマンティクスはより値型に近いものです。特に、等価性は同一性ではなく、状態に基づいています。これは、以下のことを意味します。
"abc" == "ab" + "c"
. これは不変性を必要としませんが、このような文字列への参照はその寿命を通じて常に "abc" と等しいという事実(これは不変性を必要とします)により、以前の値との等質性が不可欠なキーとしての使用は、より簡単に正確性を確保できます(実際、キーとしてよく使用される文字列です)。 -
概念的には、イミュータブルである方が理にかなっている場合もあります。クリスマスに1ヶ月追加しても、クリスマスを変えたわけではなく、1月下旬に新しい日付を生成したことになります。したがって、次のようにするのが理にかなっています。
Christmas.AddMonths(1)
は新しいDateTime
を変更するのではなく、ミュータブルなものを変更するのです。(他の例として、もし私がmutableなオブジェクトとして自分の名前を変更した場合、変更されたのは私が使っている名前であり、quot;Jon"は不変のままで、他のJonは影響を受けません。 -
コピーは高速かつシンプルで、クローンを作成するには、単に
return this
. コピーはどうせ変更できないので、何かを自分のコピーであるかのように装うことは安全です。 - [編集部、これ忘れてました]。内部状態をオブジェクト間で安全に共有することができる。例えば、配列と開始インデックスとカウントでバックされるリストを実装していた場合、サブレンジを作るのに最もコストがかかるのは、オブジェクトのコピーでしょう。しかし、もしそれが不変であれば、サブレンジオブジェクトは同じ配列を参照し、開始インデックスとカウントだけが変更され、その結果、サブレンジオブジェクトは 非常に 構築時間が大幅に短縮されます。
全体として、その目的の一部として変化する必要のないオブジェクトの場合、イミュータブルであることには多くの利点があると言えるでしょう。主な欠点は余分なコンストラクタを必要とすることですが、ここでもしばしば誇張されています(StringBuilderが同等のコンストラクタを持つ一連の連結よりも効率的になるまでに何度も追加を行わなければならないことを思い出してください)。
もし、ミュータビリティがオブジェクトの目的の一部であるならば、それは不利になるでしょうが(給料が決して変わらないEmployeeオブジェクトによってモデル化されたい人はいないでしょう)、時にはそれが役に立つこともあります(多くのWebや他のステートレスアプリケーションでは、読み取り操作を行うコードは更新を行うコードとは別で、異なるオブジェクトを使うことが自然でしょう - 私はオブジェクトを不変にしてそのパターンを強制しませんが、もし私がすでにそのパターンを持っていたら、パフォーマンスと正確性の保証のために私の "read" オブジェクトを不変にしてしまうでしょう)。
Copy-on-writeは中間的な存在です。ここでは、"real" クラスは、"state" クラスへの参照を保持しています。ステートクラスはコピー操作で共有されますが、ステートを変更すると、ステートクラスの新しいコピーが作成されます。これはC#よりもC++でよく使われます。そのため、std:stringはmutableでありながら、immutable型の利点を一部(全てではありませんが)享受しています。
関連
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] なぜパスワードにはStringではなくchar[]が好まれるのですか?
-
[解決済み] JavaでStringをintに変換するにはどうしたらいいですか?
-
[解決済み] バイトを文字列に変換する
-
[解決済み] C#で文字列のエンコーディングを手動で指定せずに、一貫性のあるバイト表現を得るには?
-
[解決済み] JavaScriptで二重引用符と単一引用符はいつ使うべきですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】大文字・小文字を区別しない「Contains(string)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】"出力タイプがクラスライブラリのプロジェクトは直接起動できない"
-
[解決済み】ソケットのアドレス(プロトコル/ネットワークアドレス/ポート)は、通常1つしか使用できない?
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み】値をNULLにすることはできません。パラメータ名:source
-
[解決済み] ...基礎となる接続は閉じられました。予期しないエラーが受信で発生しました
-
[解決済み] 関数を終了するには?
-
[解決済み】プロセスが実行されているかどうかを知るには?
-
[解決済み】Microsoft.Extensions.LoggingからILoggerを解決することができない
-
[解決済み】データが存在しないのに読み込もうとする試みが無効である
-
[解決済み】Javaや.NETで文字列がmutableにならないのはなぜ?