具有类型化参数的类上的Scala模式匹配

时间:2015-12-28 18:58:16

标签: scala generics reflection

我尝试使用类型化参数在自定义类上进行模式匹配:

class Foo[A]

def isMyFoo[A: ClassTag](v: Any) = v match {
    case mine: Foo[A] => "my foo"
    case other: Foo[_] => "not my foo"
    case _ => "not a foo"
}

这不起作用;无论Foo的类型如何,我都会得到"my foo"

我能够做出像这样的工作的唯一方法是:

class Foo[A](implicit t: ClassTag[A]) {
    val tag = t
}

def isMyFoo[A: ClassTag](v: Any) = v match {
    case foo: Foo[_] =>
        if (foo.tag == classTag[A]) "my foo"
        else "not my foo"
    case _ => "not a foo"
}

有更优雅的方式吗?我是否必须将ClassTag保留在Foo内?

1 个答案:

答案 0 :(得分:4)

  

我是否必须将ClassTag保留在Foo中?

是。 Foo的类型参数在运行时被删除,所以你知道的是你有一个Foo[_]。唯一的方法是使用ClassTagTypeTag保存类型信息。如果您要使用此路线,我建议您使用TypeTag,因为您可以使用更精致的类型。 ClassTag仍然只能模数类型擦除。

例如,使用ClassTag,这是错误的:

scala> val fooListString = new Foo[List[String]]
fooListString: Foo[List[String]] = Foo@f202d6d

scala> isMyFoo[List[Int]](fooListString)
res4: String = my foo

但以下方法可行:

class Foo[A](implicit t: TypeTag[A]) {
    val tag = t
}

def isMyFoo[A: TypeTag](v: Any) = v match {
    case foo: Foo[_] =>
        if (foo.tag.tpe =:= typeOf[A]) "my foo"
        else "not my foo"
    case _ => "not a foo"
}

scala> val fooListString = new Foo[List[String]]
fooListString: Foo[List[String]] = Foo@6af310c7

scala> isMyFoo[List[Int]](fooListString)
res5: String = not my foo