Как использовать Enum.valueOf от Scala? - PullRequest
5 голосов
/ 19 мая 2011

Мне нужно получить значение перечисления Java из строки, заданной экземпляром класса Enum. Я пробовал код, как показано ниже, но я получаю ошибку компиляции "unbound wildcard type". Кажется, мне нужно что-то делать с экзистенциальными типами, forSome {} или чем-то, но я не могу понять, как это сделать правильно.

val paramClass = method.getParameterTypes()(0)
val value = paramClass match {
  case _ if classOf[Enum[_]].isAssignableFrom(paramClass) => Enum.valueOf[_ <: Enum[_]](paramClass.asInstanceOf[Class[_ <: Enum[_]]], "MYENUM")

1 Ответ

7 голосов
/ 19 мая 2011

Хм, жесткий. У меня есть рабочее решение, но я нахожу это уродливым. Я буду заинтересован в любом более элегантном подходе!

def enumValueOf[T <: Enum[T]](cls: Class[_], stringValue: String): Enum[_] =
  Enum.valueOf(cls.asInstanceOf[Class[T]], stringValue).asInstanceOf[Enum[_]]

val value = paramClass match {
  case _ if classOf[Enum[_]].isAssignableFrom(paramClass) => enumValueOf(paramClass, "MYENUM")
  case _ => // other cases
}

Причина, по которой я думаю , нам нужна эта сложность ...

Нам нужно, чтобы компилятор полагал, что Class[_], который у нас есть, на самом деле Class[T <: Enum[T]] (поэтому, конечно, необходим предварительный тест, что это действительно перечисление Java - как сделано в вашем коде). Поэтому мы приводим cls к Class[T], где компилятор выводит T как <: Enum[T]. Но компилятор все еще должен найти подходящий T, и по умолчанию здесь Nothing. Итак, что касается компилятора, cls.asInstanceOf[Class[T]] - это Class[Nothing]. Это временно OK , так как его можно использовать для вызова Enum.valueOf - проблема в том, что предполагаемый тип возврата valueOf тогда, естественно, также Nothing. И здесь у нас есть проблема, потому что компилятор вставит исключение, когда мы попытаемся использовать экземпляр типа Nothing. Итак, мы, наконец, приведем возвращаемое значение valueOf к Enum[_].

Хитрость заключается в том, чтобы всегда позволять компилятору выводить аргумент типа на enumValueOf и никогда не пытаться указать его самостоятельно (поскольку мы все равно не должны это знать) - и, таким образом, извлечь вызов к Enum.valueOf в другом методе, дающем компилятору возможность связать T <: Enum[T].

Как я уже сказал, я не очень доволен этим решением, которое выглядит намного сложнее, чем должно быть ...

Обновление: Я немного упростил код.

...