Найдено единицы: required Int. Почему ошибка не очевидна? - программирование
Подтвердить что ты не робот

Найдено единицы: required Int. Почему ошибка не очевидна?

У меня есть метод, который должен возвращать Int. Я пытаюсь понять, почему Eclipse не позволит мне скомпилировать это, хотя мне кажется очевидным, что внутри оператора if я действительно возвращаю Int. Есть ли что-то, что я пропускаю, очень очевидно? Я пытаюсь понять этот аспект Scala, прежде чем писать больше кода.

Вот способ:

def contains1(sfType: TokenType): Int = {
     if (Tokens.KEYWORDS.contains(sfType)) {
      val retVal = TokenTypes.RESERVED_WORD
    }
  }

Eclipse жалуется на строку 2 --- 'несоответствие типа; найдено: Требуемое устройство: Int "

TokenTypes is - public abstract interface org.fife.ui.rsyntaxtextarea.TokenTypes and RESERVED_WORD is - public static final int RESERVED_WORD = 6;

Я прочитал этот пост здесь: найдено: Требуется блок: Int - Как исправить это? и попытался решить проблему, прежде чем публиковать ее, но я все еще в убыток.

Изменить: метод должен возвращать Int, и я неверно набрал тип возвращаемого значения. Моя проблема остается прежней. Eclipse все еще жалуется.

4b9b3361

Ответ 1

Сначала я объясню, какой тип Unit, на всякий случай. Даже если вы уже знаете, другие люди, имеющие такую ​​же проблему, могут не знать этого.

Тип Unit похож на то, что известно на C или Java как void. На этих языках это означает, что "это ничего не возвращает". Однако каждый метод в Scala возвращает значение.

Чтобы устранить разрыв между каждым методом, возвращающим что-то и не имеющим ничего полезного для возврата, там Unit. Этот тип является AnyVal, что означает, что он не выделяется в куче, если только он не вставлен в поле или не является типом поля на объекте. Кроме того, он имеет только одно значение, буквальное значение которого (). То есть вы можете написать это:

val x: Unit = ()

Практический эффект от этого заключается в том, что когда метод "возвращает" Unit, компилятору не нужно фактически возвращать какое-либо значение, так как оно уже знает, что это за значение. Поэтому он может реализовать методы, возвращающие Unit, объявив их на уровне байт-кода как void.

В любом случае, если вы ничего не хотите возвращать, вы возвращаете Unit.

Теперь посмотрим на приведенный код. Eclipse говорит, что возвращает Unit, и, фактически, Eclipse является правильным. Тем не менее, большинство людей действительно сделало бы ошибку того, что этот метод возвращает AnyVal или Any, а не Unit. Для примера см. Следующий фрагмент:

scala> if (true) 2
res0: AnyVal = 2

Итак, что случилось? Ну, когда Scala находит оператор if, он должен выяснить, что такое возвращаемый им тип (в выражениях Scala, if также возвращаются значения). Рассмотрим следующую гипотетическую строку:

if (flag) x else y

Очевидно, что возвращаемое значение будет либо x, либо y, поэтому тип должен быть таким, чтобы соответствовать как x, так и y. Один такой тип Any, так как все имеет тип Any. Если оба x и y имеют один и тот же тип - скажем, Int - тогда это также будет допустимым типом возврата. Поскольку Scala выбирает наиболее специфический тип, он выбирает Int над Any.

Теперь, что происходит, когда у вас нет инструкции else? Даже в отсутствие оператора else условие может быть ложным - в противном случае не было бы смысла использовать if. Что означает Scala, в этом случае нужно добавить оператор else. То есть, он перезаписывает этот оператор if следующим образом:

if (true) 2 else ()

Как я уже говорил: если вам нечего возвращать, верните Unit! Это именно то, что происходит. Поскольку Int и Unit являются AnyVal, и учитывая, что AnyVal более конкретный, чем Any, эта строка возвращает AnyVal.

До сих пор я объяснял, что видели другие, но не то, что происходит в этом конкретном коде в вопросе:

if (Tokens.KEYWORDS.contains(sfType)) {
  val retVal = TokenTypes.RESERVED_WORD
}

Мы уже видели, что Scala перепишет его следующим образом:

if (Tokens.KEYWORDS.contains(sfType)) {
  val retVal = TokenTypes.RESERVED_WORD
} else ()

Мы также видели, что Scala выберет наиболее конкретный тип между двумя возможными результатами. Наконец, Eclipse говорит, что тип возврата Unit, поэтому единственное возможное объяснение заключается в том, что тип этого:

  val retVal = TokenTypes.RESERVED_WORD

также Unit. И это точно правильно: утверждения, объявляющие вещи в Scala, имеют тип Unit. И, между прочим, делайте присваивания.

Решение, как указывали другие, состоит в том, чтобы удалить назначение и добавить оператор else, также возвращающий Int:

def contains1(sfType: TokenType): Int =
  if (Tokens.KEYWORDS.contains(sfType)) TokenTypes.RESERVED_WORD
  else -1

(примечание: я переформатировал метод, чтобы использовать стиль кодирования, более общий среди программистов Scala)

Ответ 2

У меня есть ощущение, что вам нужно изменить свой метод, чтобы выглядеть как один из следующих

def contains1(sfType: TokeType): Int = {
  if (Tokens.KEYWORDS.contains(sfType))
    TokenTypes.RESERVED_WORD
  else 
    -1
}

def contains1(sfType: TokenType) = if (Tokens.KEYWORDS.contains(sfType)) TokenTypes.RESERVED_WORD else -1

Ответ 3

В scala нет ни одного оператора if

Поскольку каждое выражение при оценке должно возвращать значение (оно может быть пустым значением типа Unit), выражение if должно всегда совпадать с ветвью else, и оба должны возвращать один и тот же тип, или в худшем случае scala выведет наиболее распространенный супертип.

В коде вы возвращаете Int из ветки if, но ветвь else отсутствует.

обновляется

Как указано в других ответах:

единственное выражение if возвращает единственную альтернативу внутри него, которая для исходного сообщения - это возвращаемое значение присваивания, которое () типа Unit

Ответ 4

Eclipse считает, что если блок "if" равен false, то есть Tokens.KEYWORDS.contains(sfType) - false, тогда тип возврата действительно будет Unit, что является проблемой.