Хм, жесткий. У меня есть рабочее решение, но я нахожу это уродливым. Я буду заинтересован в любом более элегантном подходе!
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]
.
Как я уже сказал, я не очень доволен этим решением, которое выглядит намного сложнее, чем должно быть ...
Обновление: Я немного упростил код.