Решение дано в комментарии @lasf:
def asList[C <: Content](content: C): List[C] = content match {
case A => List(A) // compiles
case b: B => List(content) // compiles
}
Проблема в том, что тип возвращаемого значения List[C]
, но компилятор не может гарантировать, что тип List(b)
равен List[C]
,В частности, C
может быть подтипом B
, в этом случае List(b)
будет List[B]
, который не совместим с List[C]
.
Обновленная версия может быть решена с использованием asInstanceOf
, хотя это не красиво.
def apply[C <: Content](content: C): Container[C] = content match {
case A => ContainerA(A) // compiles
case b: B => ContainerB(b).asInstanceOf[Container[C]]
}
В качестве альтернативы, вы можете использовать другой подход и использовать неявное преобразование:
object Container {
implicit def contain(content: A.type): Container[A.type] = ContainerA(content)
implicit def contain(content: B): Container[B] = ContainerB(content)
}
val ca: Container[A.type] = A
val cb: Container[B] = B(0)
или даже несколько конструкторов:
object Container {
def apply(content: A.type): Container[A.type] = ContainerA(content)
def apply(content: B): Container[B] = ContainerB(content)
}
Вот альтернативный дизайн с использованием класса типов .Это заменит суперкласс Content
на класс типов Containable
.Класс Container
теперь может содержать что угодно, если для этого класса существует экземпляр Containable
.
case object A
case class B(i: Int)
sealed trait Container[C]
case class ContainerA(content: A.type) extends Container[A.type]
case class ContainerB(content: B) extends Container[B]
trait Containable[T] {
def apply(value: T): Container[T]
}
object Containable {
implicit object AContainer extends Containable[A.type] {
def apply(value: A.type) = ContainerA(value)
}
implicit object BContainer extends Containable[B] {
def apply(value: B) = ContainerB(value)
}
}
object Container {
def apply[C](content: C)(implicit containable: Containable[C]): Container[C] =
containable(content)
}