Ответ 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)