Как я могу сопоставлять классы в выражении Scala "match"?
Как я могу использовать оператор "match" для определения значения переменной класса? Недопустимо следующее: я не могу найти приемлемый вариант - кроме if... else if... else...
val c: Class[_] = classOf[Int]
val what = c match { case classOf[Int] => "int!"; case classOf[Float] => "float!" }
Компилятор жалуется: error: not found: type classOf
И, конечно, я не могу использовать Class[Int]
, потому что эта информация типа удаляется:
c match { case Class[Int] => "int!"; case Class[Float] => "float!" }
error: type Class of type Class does not take type parameters.
Я также пробовал варианты вроде Int.class
, все безрезультатно. (И я действительно не хочу конвертировать в строки: я считаю важным, чтобы компилятор переименовал/переместил классы.)
Я плотный, или я наткнулся на слепое пятно Scala?
Ответы
Ответ 1
Вы можете сопоставлять значения классов, если для них создается стабильный идентификатор (т.е. a val),
scala> val c: Class[_] = classOf[Int]
c: Class[_] = int
scala> val ClassOfInt = classOf[Int]
ClassOfInt: java.lang.Class[Int] = int
scala> val ClassOfFloat = classOf[Float]
ClassOfFloat: java.lang.Class[Float] = float
scala> val what = c match {
| case ClassOfInt => "int!"
| case ClassOfFloat => "float!"
| }
what: String = int!
Обратите внимание, что вы не можете сопоставлять тип (т.е. класс [Int]), поскольку стирание означает, что экземпляры класса [T] различного типа неотличимы во время выполнения... следовательно, предупреждение ниже
scala> val what = c match {
| case _: Class[Int] => "int!"
| case _: Class[Float] => "float!"
| }
warning: there were 2 unchecked warnings; re-run with -unchecked for details
what: java.lang.String = int!
Ответ 2
Работает подробный пример сравнения:
val what = c match {
case q if q == classOf[Int] => "int!"
case q if q == classOf[Float] => "float!"
}
Конечно, будучи идентификатором в нижнем регистре, classOf
не должен работать напрямую в случае case. Однако ни один из них не сбежал из
case `classOf`[Int]
работают в этом случае, поэтому вам придется идти с if
-guard.
Ответ 3
Я столкнулся с той же проблемой, и размещение класса в "стабильном идентификаторе" было не таким практичным. Я обнаружил, что лучше всего было бы иметь инструкции "else if".
Используя этот метод:
private def is[T <: AnyRef : Manifest](implicit cls: Class[_]) =
cls == manifest[T].runtimeClass
Я могу написать:
implicit val arg = cls
if (is[ClassA]) ...
else if (is[ClassB]) ...
...
else throw new IllegalArgumentException("Unknown class: " + cls)