我们在公司使用的数据结构如下:
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]
}
在某个时候,给定一些未知的Resource
,我们希望使用模式匹配来确定其内部类型并启动一些不同的处理。
但是由于类型擦除,简单的模式匹配不起作用。因此,我们尝试使用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]
而不是具体实现。
如何使这种模式匹配起作用?
答案 0 :(得分:1)
您应该将擦除类型参数固定为某种新类型。类型别名不是新类型,只是当前类型的附加名称。
您可以执行以下操作:
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)
以消除最终用户的样板,则应使用此类创建来定义函数。消除实施
该功能的样板-我猜您可以使用宏或类似无形的东西。