4

概要

リテラル式を引数として関数に渡す場合、最初に同じリテラル式を評価し、その評価から返された値に変数をバインドし、変数名を同じ引数として渡すのと同じではありませんか?同じ機能に?そして、そのリテラル式が関数のパラメーターに対して間違った型を返す場合、Scala が式の戻り値から型を推測する中間変数に値を代入するステップをスキップしても、互換性のない型を以前の関数に渡すことはできません。型の不一致エラーが発生しましたか? しかし、それは次の例が示すものではありませんか?

Array[Super]ここでは、 の値を受け入れるタイプの関数パラメーターを取得しようとしていますArray[Sub]。Scala repl で次のように宣言します。関数の単一パラメーターの型に注意してください。

class Super
class Sub extends Super
def wantsSuperArray(a: Array[Super]) { println(a.size) }

次に、のインスタンスを構築しますSub

scala> val s = new Sub
s: Sub = Sub@2c9fa2fb

を作成しますArray[Sub]

scala> val subArray = Array(s)
subArray: Array[Sub] = Array(Sub@2c9fa2fb)

以下は、ジェネリックArrayがその要素 type で不変であること、およびaが aであってもan が anArray[Sub]ではないことを示します。Array[Super]SubSuper

scala> wantsSuperArray(subArray)
<console>:13: error: type mismatch;
 found   : Array[Sub]
 required: Array[Super]
Note: Sub <: Super, but class Array is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: Super`. (SLS 3.2.10)
              wantsSuperArray(subArray)
                              ^

これまでのところ驚くことはありません。

驚くべき観察

wantsSuperArray()引数の型として an を取りませんArray[Sub]。では、なぜ次のコードが上記と同じ型不一致エラー メッセージを生成しないのでしょうか?

scala> wantsSuperArray(Array(new Sub))
1

同様に、なぜこれでエラーが発生しないのですか?

scala> wantsSuperArray(Array(s))
1

コンパイラが repl と一貫して 3 つのバリアントを処理することを考慮してください。つまり、コンパイルを拒否し、最初の型には同じ型不一致エラーを与え、2 番目と 3 番目はコンパイルします。

追加の詳細

次のように明示的にパラメータ化するArrayと、エラー メッセージが再び表示されます。

scala> wantsSuperArray(Array[Sub](new Sub))
<console>:11: error: type mismatch;
 found   : Array[Sub]
 required: Array[Super]
Note: Sub <: Super, but class Array is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: Super`. (SLS 3.2.10)
              wantsSuperArray(Array[Sub](new Sub))
                                        ^

したがって、明らかに中間変数が含まれていない場合、Scala はどの型wantsSuperArrayが必要かを認識し、何らかの変換 (おそらく からArray[Sub]へのキャスト) を行っていることがわかりArray[Super]ます。それでも、中間変数を使用するかどうかの選択がプログラムの動作にそのような違いを引き起こすべきではないと私はまだ考えているので、それは落とし穴のように思えます.この特定の状況は、エラーを発生させる代わりにキャストを実行しているようです.プログラマーは、ジェネリックArray型パラメーターの不変性に基づいて期待します。

質問

wantsSuperArray()上で定義した呼び出しで、リテラル式を渡すことは、上に示したように、同じ式を評価した結果の値を保持する変数の名前を渡すことと同じであるべきだと私が信じている場合、私は何を誤解していますか?

  • ここで私が観察し、不平を言っていることについて、どうすれば理解を深めることができますか?

  • ここで観察している現象を理解し、二度と驚かないようにするには、Scala ドキュメントのどこで読むことができますか?

4

2 に答える 2