1
|temp|
temp := Array new: 5.
temp at: 1 put: 10.

エラーは発生しません。

|temp|
temp := #(1 2 3 4 5).
temp at: 1 put: 10.

エラーが出る

配列を初期化する 2 つの方法の違いは何ですか?

4

2 に答える 2

0

他の回答で述べたように、 #(1 2 3 4 5) は不変の配列になり、それに書き込もうとすると例外が発生します。不変コレクションの概念を導入する理由を説明したいと思いました。

Smalltalk は、ソース コードを CompiledMethod クラスのインスタンスにコンパイルします。CompiledMethod には、バイトコード (仮想マシンによって実行される命令を表すバイト) とリテラルが含まれます。リテラルは、コンパイラによって作成され、メソッドによって参照されるオブジェクトです。

次のコードを検討してください。

isSmallPrime: aNumber
    ^#(2 3 5 7 11) includes: aNumber

オブジェクト #(2 3 5 7 11) は、CompiledMethod にリテラルとして格納される配列です。問題は、リテラルの値を変更できる場合、ソース コードを変更せずにコードの動作を効果的に変更できることです。コードを見ると、1 つのことをしているように見えますが、実際には別のことをしています。

次の例を検討してください。

isSmallPrime: aNumber
    ^self smallPrimes includes: aNumber

smallPrimes
    ^#(2 3 5 7 11)

corrupt
  self smallPrimes at: 1 put: 4

破損を呼び出す場合は、smallPrimes メソッドのリテラル配列を #(4 3 5 7 11) に変更します。ソース コードでは smallPrimes が #(2 3 5 7 11) を返すと書かれていますが、実際には #(4 3 5 7 11) を返します。その後、isSmallPrime: 2 を呼び出すと false が返され、isSmallPrime: 4 を呼び出すと true が返されます。これは非常に混乱を招きます。これは、通常、メソッドが常にソース コードに記述されているとおりに動作すると想定しているためです。ここでは、ソース コードが 1 つのことを言い、メソッドが別のことを行う場合があります。

この問題を防ぐために、VisualWorks は不変リテラルの概念を導入しました。(破損したメソッドなどで) リテラル オブジェクトに書き込もうとすると、例外が発生して、コードの操作がソース コードでコードが実行することと一致することが保証されます。

于 2013-09-26T23:40:23.573 に答える