首页 > 解决方案 > scala列表与泛型的模式匹配

问题描述

我有一堂课

case class MyClass[T](values: List[T])

我正在尝试创建一个函数,该函数将根据 T 的类型返回一个值

def myFunc: T = values match {
  case v: List[Boolean] => false
  case v: List[MyType] => MyType.defaultVal
  case _ => throw new Exception("unsupported type")
}

但是,我得到编译错误:

Boolean 类型的表达式不符合预期的 T 类型

MyType.defaultVal.type 类型的表达式不符合预期的类型 T

我想我可以通过创建一个抽象类和子类来解决这个问题,但我不想这样做。有没有其他方法可以解决这个问题?

标签: scalagenericspattern-matching

解决方案


问题是模式匹配主要在运行时执行,类型在编译时解析。因为类型擦除case v: List[Boolean] => ???并不比case v: List[_] => ???. 在行case v: List[Boolean] => ...编译器不知道T =:= Boolean。模式匹配不能从不同的情况下返回不同的类型。

因此,您可以使用类型标签进行模式匹配和强制转换

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")
  } 
}

或者使用类型类(或多态函数)更安全地执行此操作

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
  }
}

推荐阅读