In an example below, I like to return any type of Container
from the function getInfos
and from the caller side to perform map with pattern matching however I get compiler error that I cannot return Container[_]
. Is there a way to return Container
of any type? If not, what is the best way to approach this?
trait Info[T] {
def value: T
}
case class ContainerAInfo(value: Long) extends Info[Long]
case class ContainerBInfo(value: String, value2: String) extends Info[String]
trait Container[T] {
def info: Info[T]
}
case class ContainerA[Long](projectionInfo: ContainerAInfo)
case class ContainerB[String](projectionInfo: ContainerBInfo)
def getInfos: Seq[Container[_]] = {
Seq(
ContainerA(
projectionInfo = ContainerAInfo(1L)
),
ContainerB(
projectionInfo = ContainerBInfo("12", "12")
)
)
}
CodePudding user response:
Long
and String
in
case class ContainerA[Long](...)
case class ContainerB[String](...)
are not standard Long
(scala.Long
) and String
(scala.Predef.String
aka java.lang.String
). You introduce new generics shadowing standard Long
and String
. It's better to switch on scalacOptions = "-Xlint:type-parameter-shadow"
to avoid such confusion
Type Arguments and Bounds in Scala
What causes this type error in a pattern guard for matching list of tuples
Strange Error with String in Scala 2.12.7
Type parameters applied to Scala Function
I suspect ContainerA
and ContainerB
are supposed to extend Container
, don't they? So a minimal change to your code making it compile is
case class ContainerA(info: ContainerAInfo) extends Container[Long]
case class ContainerB(info: ContainerBInfo) extends Container[String]
def getInfos: Seq[Container[_]] = {
Seq(
ContainerA(
info = ContainerAInfo(1L)
),
ContainerB(
info = ContainerBInfo("12", "12")
)
)
}
Container[_]
is an existential type, a minimal supertype of all Container[T]
, including Container[Long]
, Container[String]
, Container[Any]
scala - Any vs underscore in generics
Understanding scala's _ vs Any/Nothing
CodePudding user response:
You can consider making the hierarchy covariant and using Seq[Container[Any]]
:
trait Info [ T] {
def value: T
}
case class ContainerAInfo (value: Long) extends Info [Long]
case class ContainerBInfo (value: String, value2: String) extends Info [String]
trait Container [ T] {
def projectionInfo: Info [T]
}
case class ContainerA (projectionInfo: ContainerAInfo) extends Container [Long]
case class ContainerB (projectionInfo: ContainerBInfo) extends Container [String]
def getInfos: Seq [Container [Any]] =
Seq (
ContainerA (
projectionInfo = ContainerAInfo (1L)
), ContainerB (
projectionInfo = ContainerBInfo ("12", "12")
)
)
Though possibly it will not be that useful.