Class 我可以在Scala match语句中使用类变量吗?

Class 我可以在Scala match语句中使用类变量吗?,class,scala,Class,Scala,假设我有这样的东西: obj match { case objTypeOne : TypeOne => Some(objTypeOne) case objTypeTwo : TypeTwo => Some(objTypeTwo) case _ => None } obj match { case objTypeTwo : TypeTwo => Some(objTypeTwo) case objTypeOne if clazz.is

假设我有这样的东西:

obj match {
    case objTypeOne : TypeOne => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}
obj match {
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case objTypeOne if clazz.isAssignableFrom(objTypeOne.getClass) => Some(clazz.cast(objTypeOne))
    case _ => None
}
现在我想概括一下,传入一种要匹配的类型:

obj match {
    case objTypeOne : clazz => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}
但这是不允许的,我认为这是出于语法而非语义的原因(尽管我猜即使clazz是一个类[C],类型也会被删除,因此选项的类型会丢失)

我的结局是:

if(clazzOne.isAssignableFrom(obj.getClass)) Some(clazz.cast(obj))
if(obj.isInstanceOf[TypeTwo]) Some(obj.asInstanceOf[TypeTwo])
None

我只是想知道是否有更好的方法。

您可以使用图案保护来实现这一点。试着这样做:

obj match {
    case objTypeOne : TypeOne => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}
obj match {
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case objTypeOne if clazz.isAssignableFrom(objTypeOne.getClass) => Some(clazz.cast(objTypeOne))
    case _ => None
}

可以定义与对象匹配的提取器:

class IsClass[T: Manifest] {
  def unapply(any: Any): Option[T] = {
    if (implicitly[Manifest[T]].erasure.isInstance(any)) {
       Some(any.asInstanceOf[T])
    } else {
       None
    }
  }
}
让我们来测试一下:

class Base { def baseMethod = () }
class Derived extends Base

val IsBase = new IsClass[Base]

def test(a:Any) = a match {
    case IsBase(b) => 
      println("base")
      b.baseMethod
    case _ => println("?")
  }

test(new Base)
test(1)
您必须为提取器定义val,例如,您不能内联
IsBase
。否则,它将被解释为提取器。

您可以使用本地类型别名:

def matcher[T](obj: Any)(implicit man: Manifest[T]) = {
   val instance = man.erasure.newInstance.asInstanceOf[AnyRef]
   type T = instance.type // type alias
   obj match { 
      case objTypeOne : T => "a"
      case objTypeTwo : TypeTwo => "b"
      case _ => "c"
   }
}

scala> matcher[TypeOne](TypeOne())
res108: java.lang.String = a

scala> matcher[TypeTwo](TypeOne())
res109: java.lang.String = c

更新:Aaron Novstrup指出,只有当
man.erasure.newInstance==obj
(请参见规范的§3.2.1)时,单例类型才会起作用。

这看起来很好,但我不知道如何将类型别名作为参数传入。我试图找到某个类的某些内容,传入该类(目前是一个类[C]),我有不同的方法查找不同的类。我不认为这是@Dan的意图。为了使
obj2
的类型为
obj1.type
,它必须等于
obj1
.No
obj1
只是与
obj2
类型相同的实例-对象不应相等。@Vasil 1)此代码假定t具有无参数构造函数。2) 它不在Scala 2.8.0 REPL中编译。3) 如果
obj!=man.erasure.newInstance
。原因见规范§3.2.1:“单态类型[…]p.type[…]表示由null和p表示的值组成的一组值”。