Обобщение несоответствия типов с classOf Scala - PullRequest
1 голос
/ 05 января 2020

У меня есть метод, который должен динамически преобразовывать член поля в определенный тип в зависимости от флага конфигурации format.

Этот флаг format принимает одно из следующих значений типа:

object Types {
    val Str = "string"
    val IntNum1 = "int"
    val IntNum2 = "integer"
    val DoubleNum = "double"
    val LongNum = "long"
}

Один из вариантов - использовать отражение. Другой вариант - использовать сопоставление с образцом (метод, с которым я пытаюсь это сделать)

Вот метод для String типов:

private def getValClassIfStr(format: String): Class[String] = {
    format.toLowerCase match {
        case Types.Str => classOf[String]
        case _ => null
    }
}

А вот метод для числового типы, начиная с AnyVal, которые не компилируются:

private def getValueClass[T <: AnyVal](format: String): Try[Class[T]] = {
    format.toLowerCase match {
        case Types.IntNum1 || Types.IntNum2 => Success(classOf[Int])
        case Types.DoubleNum => Success(classOf[Double])
        case Types.LongNum => Success(classOf[Long])
        case _ => Failure(new Exception)
    }
}

Второй метод не компилируется из-за: Type mismatch: required Try[Class[T]] found Try[Class[Int]]

Что я не понимаю, учитывая T <: AnyVal.

Есть идеи? и если это плохой подход, какой будет «чистая» альтернатива?

1 Ответ

1 голос
/ 06 января 2020

Я думаю, что причина, по которой это не работает, становится яснее, когда вы замените Class[T] в возвращаемом значении на Class[AnyVal]:

type mismatch;
 found   : Class[Int](classOf[scala.Int])
 required: Class[AnyVal]
Note: Int <: AnyVal, but Java-defined class Class is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: AnyVal`. (SLS 3.2.10)

Другими словами, любой вызов getValueClass[T] будет всегда должен заполняться T = AnyVal компилятором, поскольку format оценивается только во время выполнения. Это, однако, невозможно, поскольку Class[T] является инвариантом, поэтому вы не можете вернуть Class[Int] и Class[Double] в качестве Class[AnyVal], поскольку для инвариантных контейнеров отношения подтипов отсутствуют.

Для демонстрации:

var x: Class[AnyVal] = _
x = classOf[Int]
// Boom
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...