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を渡しています。ここで何かが間違いなく間違っています - どの行が原因ですか? 答えは、メソッド宣言です。この問題を解決するには、共変の型パラメーターを反変の位置 (宣言内) から削除する必要があります。あるいは、非共変にすることもできます。IntvaluesList[Any]IntAnyconsAconsA
次の質問も参照してください: #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はそれぞれdogandtigerのインスタンスであると仮定します。DogTiger
animal_list.cons(tiger)呼び出しでは、 と タイプ パラメータの両方がAにBインスタンス化されるAnimalため、consメソッドは次の形式になります。
def cons[Animal >: Animal](v: Animal): List[Animal]
Animal >: Animal制約は次の理由で満たされます。
スーパータイプとサブタイプの関係は再帰的です。つまり、タイプはそれ自体のスーパータイプであると同時にサブタイプでもあります。[ソース]
への引数consはTigertype に準拠してAnimalいるため、メソッド呼び出しは正しい型です。
のようBにインスタンス化を強制すると、この呼び出しは型が正しくなくなり、コンパイラ エラーが発生することに注意してください。Tigeranimal_list.cons[Tiger](tiger)
ここで同様の例を参照してください。