Могу ли я использовать переменную класса в операторе сопоставления Scala? - PullRequest
2 голосов
/ 05 ноября 2010

Скажем, у меня есть что-то вроде этого:

obj match {
    case objTypeOne : TypeOne => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}

Теперь я хочу обобщить, передать один из типов для соответствия:

obj match {
    case objTypeOne : clazz => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}

Но это не разрешеноЯ думаю, что по синтаксическим, а не по семантическим причинам (хотя я также предполагаю, что, хотя clazz - это Class [C], тип стирается, и поэтому тип Option будет утерян).с:

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

Мне просто интересно, есть ли более хороший путь.

Ответы [ 3 ]

11 голосов
/ 05 ноября 2010

Вы можете определить экстрактор, чтобы он соответствовал вашему объекту:

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, например.В противном случае это будет интерпретировано как экстрактор.

5 голосов
/ 05 ноября 2010

Вы можете использовать шаблонную охрану для достижения этой цели. Попробуйте что-то вроде этого:

obj match {
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case objTypeOne if clazz.isAssignableFrom(objTypeOne.getClass) => Some(clazz.cast(objTypeOne))
    case _ => None
}
2 голосов
/ 05 ноября 2010

Для этого вы можете использовать псевдоним локального типа:

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

ОБНОВЛЕНИЕ: Аарон Новструп отметил, что синглтон-тип будет работать, только если man.erasure.newInstance==obj (см. п. 3.2.1 спецификации)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...