Pattern match of scala list with generics [duplicate]

戏子无情 提交于 2019-12-22 18:14:18

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!