与泛型匹配的模式

时间:2011-03-19 23:54:47

标签: scala

给定以下类模式匹配:

clazz match {
  case MyClass => someMethod[MyClass]
}

是否可以根据模式匹配的内容以通用方式引用MyClass?例如,如果我有多个MyClass子类,我可以编写一个简单的模式匹配来将匹配的类型传递给someMethod

clazz match {
  case m <: MyClass => someMethod[m]
}

2 个答案:

答案 0 :(得分:7)

不幸的是,在Scala中,类型并不是真正的一等公民。这意味着您无法对类型进行模式匹配。由于从Java平台继承的愚蠢类型擦除,丢失了大量信息。

我不知道是否有任何改进请求,但这是我选择中最严重的问题之一,所以有人应该提出这样的请求。

事实是,你需要传递证据参数,最好以隐式参数的形式传递。

我能想到的最好的就是

class PayLoad

trait LowPriMaybeCarry {
   implicit def no[C] = new NoCarry[C]
}
object MaybeCarry extends LowPriMaybeCarry {
   implicit def canCarry[C <: PayLoad](c: C) = new Carry[C]
}

sealed trait MaybeCarry[C]
final class NoCarry[C] extends MaybeCarry[C]
final class Carry[C <: PayLoad] extends MaybeCarry[C] {
   type C <: PayLoad
}

class SomeClass[C <: PayLoad]

def test[C]( implicit mc: MaybeCarry[C]) : Option[SomeClass[_]] = mc match {
   case c: Carry[_] => Some(new SomeClass[ c.C ])
   case _ => None
}

但我仍然无法理解工作:

test[String]
test[PayLoad]  // ouch, not doin it
test[PayLoad](new Carry[PayLoad])  // sucks

因此,如果你想保存自己严重的脑损伤,我会忘记这个项目或寻找另一种语言。也许Haskell在这里更好?我仍然希望我们最终可以匹配类型,但我的希望非常低。

也许来自scalaz的人提出了一个解决方案,他们几乎利用了Scala的类型系统达到极限。

答案 1 :(得分:0)

您的代码并不是很清楚,因为至少在java clazz中,java.lang.Class类型变量的典型名称和变体。我仍然认为clazz不是Class的实例,而是您自己班级的实例。

在Java和Scala中,给定一个对象o:AnyRef,您可以通过o.getClass: Class[_]在运行时访问其类,例如,通过Reflection API创建该类的实例。但是,类型参数在编译时传递,因此您无法在编译时按原样传递类型。您可以在整个地方使用AnyRef作为类型(我会假设它可以使用),或者如果您有更高级的需求,则使用反射API。