问题
trait Account[T <: Account[T]]
case class BrokerAccount(total:BigDecimal) extends Account[BrokerAccount]
case class SavingsAccount(total:BigDecimal) extends Account[SavingsAccount]
Below function declaration and invocation works fine.
def foo1( xs: Array[T forSome { type T <: Account[T] }]):Array[T forSome { type T <: Account[T] }] = xs
foo1(Array(BrokerAccount(100),SavingsAccount(50)))
But below invocation gives compilation error.
def foo2( xs: List[T forSome { type T <: Account[T] }]):List[T forSome { type T <: Account[T] }] = xs
foo2(List(BrokerAccount(100),SavingsAccount(50)))
Error
Main.scala:14: error: type mismatch;
found : List[Product with Serializable with Main.Account[_ >: Main.SavingsAccount with Main.BrokerAccount <: Product with Serializable with Main.Account[_ >: Main.SavingsAccount with Main.BrokerAccount <: Product with Serializable]]]
required: List[T forSome { type T <: Main.Account[T] }] foo2(List(BrokerAccount(100),SavingsAccount(50)))
Can someone please explain me why compilation error occur in later case?
回答1:
The key to the problem is variance - you're trying to return a contravariant value in covariant position (function return type).
Despite List
type is covariant in its argument (trait List[+A]
), this essentially means its values are contravariant (can be assigned to a List of supertypes):
val listOfSupers: List[_ >: Account[_]] = List(BrokerAccount(100), SavingsAccount(50))
What you're trying to return from the function foo2
is a complete contrary - List[_ <: Account[_]]
, thus the compiler error.
If instead of List
you use Set
there, which is invariant in its type parameter just like Array
, everything will work fine.
来源:https://stackoverflow.com/questions/37432383/scala-f-bounded-type-polymorphism