给定课程
sealed abstract class A
case class B(param: String) extends A
case class C(param: Int) extends A
trait Z {}
class Z1 extends Z {}
class Z2 extends Z {}
def zFor[T <: A : Manifest]: Option[Z] = {
val z = manifest[T].erasure
if (z == classOf[B]) {
Some(new Z1)
} else
if (z == classOf[C]) {
Some(new Z2)
} else {
None
}
}
我认为模式匹配的问题是不可能在字节码中构建模式匹配表。这个问题有解决方法吗?可能是我可以使用编译器在Manifest中生成的一些Int吗?
答案 0 :(得分:2)
如果您有更复杂的类层次结构,那么您编写它的方式就不是很强大,因为如果您有一个类D <: C
,那么classOf[D] != classOf[C]
。所以你真的不想模式匹配。但你可以;你不能在模式匹配中调用classOf[X]
,但你可以
def zFor[T <: A : Manifest]: Option[Z] = {
val ClassB = classOf[B]
val ClassC = classOf[C]
manifest[T].erasure match {
case ClassB => Some(new Z1)
case ClassC => Some(new Z2)
case _ => None
}
}
只要您确定自己处于只需要检测类层次结构叶子的情况。 (您应该通过标记B
和C
final
来确保。)
或者,您可以使用isAssignableFrom
执行运行时测试:
def zFor2[T <: A : Manifest]: Option[Z] = {
manifest[T].erasure match {
case x if classOf[B].isAssignableFrom(x) => Some(new Z1)
case x if classOf[C].isAssignableFrom(x) => Some(new Z2)
case _ => None
}
}
现在
class D extends C(5) {}
scala> zFor[D]
res5: Option[Z] = None
scala> zFor2[D]
res6: Option[Z] = Some(Z2@2556af33)
答案 1 :(得分:1)
我不确定这是否适合你的问题(因为你可能已经展示了一个简化的例子)。但是可以在不使用反射的情况下创建这种功能。
这是一种非常常见的模式,允许您在不修改原始代码的情况下创建添加更多组合。
// the - here allows D to return the instance for C
// if you only want exact matches, remove the -
trait GetZ[-X] {
type Out
def z: Option[Out]
}
trait LowerPriority {
implicit def noZ[A] =
new GetZ[A] {
type Out = Nothing
val z = None
}
}
object GetZ extends LowerPriority {
implicit def forB =
new GetZ[B] {
type Out = Z1
def z = Some(new Z1)
}
implicit def forC =
new GetZ[C] {
type Out = Z2
def z = Some(new Z2)
}
}
def zFor[T](implicit getZ: GetZ[T]): Option[getZ.Out] = getZ.z
用法
class D extends C(5)
val noZ = zFor[A]
val Some(z1) = zFor[B]
val Some(z2) = zFor[C]
val Some(other_z2) = zFor[D]