我可以在Scala中对类型参数执行匹配以查看它是否实现了特征?

cod*_*fly 16 scala

我想有一个方法返回某个类的类,但我希望该方法的行为不同,具体取决于类是否扩展特定的特征,如下所示:


case class ClassA extends TraitA
case class ClassB extends TraitB
case class ClassC extends TraitA
...
def myfunc[T]():T = {
  T match {
    case TraitA => // return new T in a particular way 
    case TraitB => // ditto
  }
}

这是可能的,还是我以错误的方式去做?

谢谢

Rex*_*err 15

您不能直接比较类型,因为没有任何可比较的东西(在运行时,由于擦除).你可以处理你的班级的代表:

trait TraitA { }
trait TraitB { }
class ClassA extends TraitA { }
class ClassB extends TraitB { }

def myFunc[T](clazz: Class[T]) = {
  if (classOf[TraitA] isAssignableFrom clazz) println("A")
  else if (classOf[TraitB] isAssignableFrom clazz) println("B")
  else println("?")
}

scala> myFunc(classOf[ClassA])
A

scala> myFunc(classOf[String])
?
Run Code Online (Sandbox Code Playgroud)

或者您可以在类的实例上进行模式匹配:

def myFunc2[T](t: T) = t match {
  case _: TraitA => println("A")
  case _: TraitB => println("B")
  case _ => println("?")
}

scala> myFunc2(new ClassA)
A

scala> myFunc2(Some(5))
?
Run Code Online (Sandbox Code Playgroud)

您还可以通过类清单以语法上不那么突兀的方式使用第一种方法:

def myFunc3[T](implicit mf: ClassManifest[T]) = {
  val clazz = mf.erasure
  if (classOf[TraitA] isAssignableFrom clazz) println("A")
  else if (classOf[TraitB] isAssignableFrom clazz) println("B")
  else println("?")
}

scala> myFunc3[ClassA]
A

scala> myFunc3[String]
?
Run Code Online (Sandbox Code Playgroud)

如果if/else变得很糟糕,你也可以选择不同类型的调度:

object MyFunc {
  val dispatch = Map(
    classOf[TraitA] -> (() => println("A")),
    classOf[TraitB] -> (() => println("B"))
  )
  val default = () => println("?")
  def apply[T](implicit mf: ClassManifest[T]) = 
    dispatch.find(_._1 isAssignableFrom mf.erasure).map(_._2).getOrElse(default)()
}

scala> MyFunc[ClassA]
A

scala> MyFunc[String]
?
Run Code Online (Sandbox Code Playgroud)

请注意,您使用此代码的任何通用代码都需要具有可用的类清单(作为隐式参数或简写,[T: ClassManifest].