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

时间:2011-03-30 11:42:48

标签: 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
  }
}

这可能吗,还是我错误的方式?

由于

3 个答案:

答案 0 :(得分:14)

你无法直接比较类型,因为没有任何东西可供比较(在运行时,由于erasure)。你可以处理你班级的代表:

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])
?

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

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

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

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

如果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]
?

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

答案 1 :(得分:2)

“希望方法的行为方式不同,具体取决于类是否扩展了特定的特征”

这几乎是对继承的规范描述。难道你不能在每个特征中都有一个方法来封装你所追求的不同行为吗?

答案 2 :(得分:1)

您需要一个实例来检查类型。泛型本身只是一种类型的占位符。你可以这样做:

trait bTrait //common base trait
trait TraitA extends bTrait
trait TraitB extends bTrait

class ClassA extends TraitA
class ClassB extends TraitB

def myFunc[T <: bTrait](t:T) : String = //passing explicitly an instance of type T
{
  t match {
    case _ : TraitA => "TraitA"
    case _ : TraitB => "TraitB" 
  }
}

println(myFunc(new ClassA)) //prints TraitA