Полиморфизм F-ограниченного типа в Scala

trait Account[T <: Account[T]]

case class BrokerAccount(total:BigDecimal) extends Account[BrokerAccount]
case class SavingsAccount(total:BigDecimal) extends Account[SavingsAccount]

Ниже объявление функции и вызов работают нормально.

def foo1( xs: Array[T forSome { type T <: Account[T] }]):Array[T forSome { type T <: Account[T] }] = xs
foo1(Array(BrokerAccount(100),SavingsAccount(50)))

Но ниже вызов дает ошибку компиляции.

def foo2( xs: List[T forSome { type T <: Account[T] }]):List[T forSome { type T <: Account[T] }] = xs
foo2(List(BrokerAccount(100),SavingsAccount(50)))

Ошибка

Main.scala:14: ошибка: несоответствие типов;
найдено: List[Product with Serializable with Main.Account[_ >: Main.SavingsAccount with Main.BrokerAccount ‹: Product with Serializable with Main.Account[_ >: Main .SavingsAccount с Main.BrokerAccount ‹: Product with Serializable]]]
требуется: List[T forSome { type T ‹: Main.Account[T] }] foo2(List(BrokerAccount(100),SavingsAccount(50)) )

Может кто-нибудь объяснить мне, почему ошибка компиляции возникает в более позднем случае?


person R.M    schedule 25.05.2016    source источник


Ответы (1)


Ключом к проблеме является дисперсия - вы пытаетесь вернуть контравариантное значение в ковариантной позиции (тип возвращаемого значения функции). Несмотря на то, что тип List является ковариантным в своем аргументе (trait List[+A]), это по существу означает, что его значения контравариантны (могут быть присвоены списку супертипов):

val listOfSupers: List[_ >: Account[_]] = List(BrokerAccount(100), SavingsAccount(50))

То, что вы пытаетесь вернуть из функции foo2, является полной противоположностью - List[_ <: Account[_]], поэтому ошибка компилятора.

Если вместо List использовать там Set, который инвариантен в своем параметре типа так же, как и Array, то все будет работать нормально.

person Sergey    schedule 25.05.2016
comment
Как тогда компилируется строка ниже? foo2( List[T forSome { type T ‹: Account[T] }](BrokerAccount(100),SavingsAccount(50))) - person R.M; 25.05.2016
comment
Подробнее: stackoverflow.com /вопросы/6684493/ - person Al M; 25.05.2016