问题
I have a class
case class MyClass[T](values: List[T])
and I'm trying to create a function which will return a value based on the type of T
def myFunc: T = values match {
case v: List[Boolean] => false
case v: List[MyType] => MyType.defaultVal
case _ => throw new Exception("unsupported type")
}
However, I get compilation errors:
Expression of type Boolean doesn't conform to expected type T
Expression of type MyType.defaultVal.type doesn't conform to expected type T
I guess I can solve this by creating an abstract class ans subclasses, but I'd rather not do it this way. Is there any other way to solve this?
回答1:
I think you can solve it with scala's type tag but I'm not an expert in that field, always found this too complicated.
A simpler solution I like to use is to pattern match on the head's element:
def myFunc: T = values.headOption.map {
case v: Boolean => false
case v: MyType => MyType.defaultVal
case _ => throw new Exception("unsupported type")
}.getOrElse(throw new Exception("unsupported type"))
回答2:
The thing is that pattern matching is performed mostly at runtime and types are resolved at compile time. Because of type erasure case v: List[Boolean] => ??? is not better than case v: List[_] => ???. In the line case v: List[Boolean] => ... compiler doesn't know that T =:= Boolean. Pattern matching can't return different types from different cases.
So you can either pattern match with type tags and casting
case class MyClass[T](values: List[T]) {
import reflect.runtime.universe.{TypeTag, typeOf}
def myFunc(implicit typeTag: TypeTag[T]): T = values match {
case v: List[Boolean] if typeOf[T] <:< typeOf[Boolean] => false.asInstanceOf[T]
case v: List[MyType] if typeOf[T] <:< typeOf[MyType] => MyType.defaultVal.asInstanceOf[T]
case _ => throw new Exception("unsupported type")
}
}
or do this more type-safely with a type class (or polymorphic function)
case class MyClass[T](values: List[T]) {
def myFunc(implicit myFuncInstance: MyFunc[T]): T = myFuncInstance(values)
}
trait MyFunc[T] {
def apply(values: List[T]): T
}
object MyFunc {
implicit val booleanMyFunc: MyFunc[Boolean] = new MyFunc[Boolean] {
override def apply(values: List[Boolean]): Boolean = false
}
implicit val myTypeMyFunc: MyFunc[MyType] = new MyFunc[MyType] {
override def apply(values: List[MyType]): MyType = MyType.defaultVal
}
}
来源:https://stackoverflow.com/questions/52697227/pattern-match-of-scala-list-with-generics