4

给定的类

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 吗?

4

2 回答 2

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)
于 2013-05-19T18:01:39.507 回答
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]
于 2014-10-21T21:38:28.313 回答