Ошибка аннотации в Scala tailrec - PullRequest
4 голосов
/ 23 декабря 2010

У меня есть абстрактный класс Java с именем ImmutableEntity и несколько подклассов, которые содержат аннотацию на уровне класса с именем @DBTable.Я пытаюсь найти иерархию классов для аннотации, используя хвостовой рекурсивный метод Scala:

  def getDbTableForClass[A <: ImmutableEntity](cls: Class[A]): String = {
    @tailrec
    def getDbTableAnnotation[B >: A](cls: Class[B]): DBTable = {
      if (cls == null) {
        null
      } else {
        val dbTable = cls.getAnnotation(classOf[DBTable])
        if (dbTable != null) {
          dbTable
        } else {
          getDbTableAnnotation(cls.getSuperclass)
        }
      }
    }

    val dbTable = getDbTableAnnotation(cls)
    if (dbTable == null) {
      throw new
              IllegalArgumentException("No DBTable annotation on class " + cls.getName)
    } else {
      val value = dbTable.value
      if (value != null) {
        value
      } else {
        throw new
                IllegalArgumentException("No DBTable.value annotation on class " + cls.getName)
      }
    }
  }

Когда я компилирую этот код, я получаю сообщение об ошибке: «не удалось оптимизировать аннотированный метод @tailrec: этовызывается рекурсивно с аргументами разных типов ".Что не так с моим внутренним методом?

Спасибо.

Ответы [ 3 ]

16 голосов
/ 24 декабря 2010

Это из-за способа, которым компилятор реализует хвостовую рекурсию по циклам. Это делается как один шаг в цепочке преобразований из байт-кодов Scala в Java. Каждое преобразование должно создавать программу, которая снова является верной для типа. Однако вы не можете изменить тип переменных при выполнении в середине цикла, поэтому компилятор не может развернуться в цикл с корректным типом.

3 голосов
/ 24 декабря 2010

Могу ли я предложить более краткую версию кода?

def getDbTableForClass[A <: ImmutableEntity](cls: Class[A]): String = {
@tailrec
def getDbTableAnnotation[B >: A](cls: Class[B]): DBTable = cls match {
  case null => null
  case c if c.isAnnotationPresent(classOf[DBTable]) => c.getAnnotation(classOf[DBTable])
  case other => getDbTableAnnotation(other.getSuperclass)
}

getDbTableAnnotation(cls) match {
  case null => throw new IllegalArgumentException("No DBTable annotation on class " + cls.getName)
  case dbTable if dbTable.value ne null => dbTable.value
  case other => throw new IllegalArgumentException("No DBTable.value annotation on class " + cls.getName)
}

}

2 голосов
/ 23 декабря 2010

Поскольку параметр типа B и его граница не являются строго обязательными, вместо этого вы можете использовать экзистенциальный тип,

@tailrec
def getDbTableAnnotation(cls: Class[_]): DBTable = {
  ...
}

Scala принимает это определение для хвостовых рекурсивных вызовов.

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