cons
のパラメータ タイプが間違っているのはなぜですか?
trait List[+A] {
def cons(hd: A): List[A]
}
コンパイラはエラーを出します:
covariant type A occurs in contravariant position in type A of value hd
メソッドパラメータは反変の位置としてカウントされますが、A
共変であるためです。
このメソッド宣言がコンパイルされると想像してみましょう。次に、次のことができます。
class ListImpl[A] extends List[A] {
override def cons(hd: A): List[A] = ???
}
val strings: List[String] = new ListImpl[String]
val values: List[Any] = strings // OK, since List[String] <: List[Any] (in List[A], A is covariant)
values.cons(13) // OK(??), since values's static type is List[Any], so argument of cons should be Any, and 13 conforms to type Any
上記の最後の行は本当に OK ですか? を呼び出しcons
ていvalues
ます。values
と同じでstrings
、strings
型のオブジェクトですListImpl[String]
。したがってcons
、最後の行の呼び出しは引数を期待していますが、の静的型はであり、 に準拠しているため、String
を渡しています。ここで何かが間違いなく間違っています - どの行が原因ですか? 答えは、メソッド宣言です。この問題を解決するには、共変の型パラメーターを反変の位置 (宣言内) から削除する必要があります。あるいは、非共変にすることもできます。Int
values
List[Any]
Int
Any
cons
A
cons
A
次の質問も参照してください: #1、#2。
cons
...問題に遭遇していませんか?
trait List[+A] {
def cons[B >: A](v: B): List[B]
}
val animal_list: List[Animal] = List(tiger, dog) // We are assuming that List.apply and concrete implementation of List is somewhere defined.
いいえ、animal_list.cons(tiger)
呼び出しは正しいタイプです。
Animal
は andの共通のスーパータイプでDog
ありTiger
、 andはそれぞれdog
andtiger
のインスタンスであると仮定します。Dog
Tiger
animal_list.cons(tiger)
呼び出しでは、 と タイプ パラメータの両方がA
にB
インスタンス化されるAnimal
ため、cons
メソッドは次の形式になります。
def cons[Animal >: Animal](v: Animal): List[Animal]
Animal >: Animal
制約は次の理由で満たされます。
スーパータイプとサブタイプの関係は再帰的です。つまり、タイプはそれ自体のスーパータイプであると同時にサブタイプでもあります。[ソース]
への引数cons
はTiger
type に準拠してAnimal
いるため、メソッド呼び出しは正しい型です。
のようB
にインスタンス化を強制すると、この呼び出しは型が正しくなくなり、コンパイラ エラーが発生することに注意してください。Tiger
animal_list.cons[Tiger](tiger)
ここで同様の例を参照してください。