scala 如何使用继承和模板的模式匹配 class

scala how to use pattern matching with inheriance and templated class

我们公司使用的数据结构如下所示:

trait Resource

case class templatedResource[T](t: T) extends Resource

case class BParameter()
case class CParameter()

object B {
  type Resource = templatedResource[BParameter]
}

object C {
  type Resource = templatedResource[CParameter]
}

在某些时候,给定一些未知的 Resources 我们想使用模式匹配来确定它们的内部类型并启动一些不同的处理。

但是由于类型擦除,简单的模式匹配不起作用。所以我们尝试使用 TypeTags,但没有成功:

import scala.reflect.runtime.universe._

object Service {

  def process(resource: Resource)(implicit tag: WeakTypeTag[Resource]) = {
    (tag.tpe, resource) match {
      case (t, b: B.Resource) if t =:= typeOf[B.Resource] =>
        println("b !!")
      case (t, c: C.Resource) if t =:= typeOf[C.Resource] => 
        println("c !!")
      case _ => 
          throw new IllegalStateException(s"Unexpected resource type")
    }
  }
}

val bParam = BParameter()
val bResource: B.Resource = templatedResource(bParam)

Service.process(bResource)
//  throws java.lang.IllegalStateException: Unexpected resource type
//         at Service$.process(<console>:26)

似乎 t =:= typeOf[B.Resource] 总是错误的,因为 t 只知道 Resource 特征 ( t =:= typeOf[Resource] ) 而不知道具体实现。

我怎样才能让这个模式匹配起作用?

您应该将您的擦除类型参数修正为一些新类型。类型别名不是新类型,只是当前类型的附加名称。

你可以这样做:

trait Resource

class templatedResource[T](t: T) extends Resource

case class BParameter()
case class CParameter()

object B {
  case class Resource(val b: BParameter) extends templatedResource[BParameter](b)
}

object C {
  type Resource = templatedResource[CParameter]
}

def process(r: Resource) = {
  r match {
    case a: B.Resource => true
  }
}

process(B.Resource(BParameter()))

如果您需要保留创建语法 val bResource: B.Resource = templatedResource(bParam) 以消除 end-user 的样板 - 您应该使用此类创建来定义函数。消除实施 函数的样板 - 我猜你可以使用宏或类似 shapeless 的东西。