Дополнительно
В чем разница между "def" и "val" для определения функции
В чем разница между:
def even: Int => Boolean = _ % 2 == 0
и
val even: Int => Boolean = _ % 2 == 0
Оба могут называться как even(10)
.
205
8
Метод
def even
оценивается при вызове и каждый раз создает новую функцию (новый экземплярFunction1
).С помощью
def
вы можете получать новую функцию при каждом вызове:val
оценивает при определении,def
- при вызове:Обратите внимание, что существует и третий вариант:
lazy val
.Он оценивается при первом вызове:
Но каждый раз возвращает один и тот же результат (в данном случае один и тот же экземпляр
FunctionN
):Производительность
val
оценивает, когда определено.def
оценивается при каждом вызове, поэтому производительность может быть хуже, чем уval
при нескольких вызовах. Вы получите ту же производительность при одном вызове. А при отсутствии вызовов вы не получите никаких накладных расходов отdef
, поэтому вы можете определить его, даже если не будете использовать его в некоторых ветвях.С
ленивым val
вы получите ленивую оценку: вы можете определить его, даже если не будете использовать его в некоторых ветвях, и он оценивается один раз или никогда, но вы получите небольшие накладные расходы от двойной проверки блокировки при каждом обращении к вашемуленивому val
.Как отметил @SargeBorsch, вы можете определить метод, и это самый быстрый вариант:
Но если вам нужна функция (а не метод) для композиции функций или для функций более высокого порядка (например,
filter(even)
), компилятор будет генерировать функцию из вашего метода каждый раз, когда вы используете его как функцию, поэтому производительность может быть немного хуже, чем сval
.Подумайте об этом:
Видите разницу? Вкратце:
def: Для каждого вызова
even
, он снова вызывает тело методаeven
. А в случае сeven2
, то есть val, функция инициализируется только один раз при объявлении (и поэтому печатаетval
в строке 4 и больше никогда) и при каждом обращении используется один и тот же вывод. Например, попробуйте сделать следующее:Когда
x
инициализируется, значение, возвращаемоеRandom.nextInt
, устанавливается в качестве конечного значенияx
. В следующий раз, когдаx
будет использоваться снова, он всегда будет возвращать одно и то же значение.Можно также лениво инициализировать
x
. То есть при первом использовании он инициализируется, а не во время объявления. Например:См. это:
Удивительно, но это выведет 4, а не 9! val (даже var) оценивается сразу и присваивается.
Теперь замените val на def... будет выведено 9! Def - это вызов функции. Она будет оцениваться каждый раз, когда ее вызывают.
Валь, т. е. на "ьquot кв.&; по определению Scala является фиксированной. Она оценивается прямо во время объявления, вы можете't изменить позже. В других примерах, где even2 также Вэл, но она заявила, с функцией подписи, т. е. на "(Инт => логическое значение) - то", так это не типа int. Это функция и она'значение определяется следующим выражением
Согласно Скала собственность Валь, вы можете'т назначить другую функцию для even2, же правило, как КВ.
О том, почему вызов eval2 Валь функция не печатать на "Вэл" снова и снова ?
Код ориг:
Мы знаем, в последнем заявлении Скала выше своеобразное выражение (внутри { .. }) фактически вернуться к левой стороне. Так что вы в конечном итоге установка even2, чтобы "Х => х % 2 == 0 и" функция, которая совпадает с типом вы объявили для even2 вал типа т. е. (Инт => булево), так что компилятор счастлив. Теперь even2 только очков, чтобы "(Х => х % 2 == 0)" по функции (не любое другое заявление, т. е. код println (на"вал", У) и т. д. Вызов event2 с разными параметрами будет на самом деле ссылаться на "(Х => х % 2 == 0)" и код, а только то, что сохраняется с event2.
Просто для уточнения более этого, следующим разные версии кода.
Что будет ? здесь мы видим, что "внутри окончательной ФН" и печатается снова и снова, когда вы называете even2().
Выполнение определения, такие как
деф х = е
не будет оценивать выражение e. В - Стед e вычисляется всякий раз, когда х вызывается.Кроме того, Scala предлагает определение стоимости
Валь X = Е
,который оценит правой стороне в рамках оценки определение. Если x затем используется, он немедленно заменяется на предварительно вычисленные значения е, так что выражение не следует снова оценить.В REPL,
вызов по имени Def означает``, оценивали по требованию
вызов по значению Валь означает``, оценивается в процессе инициализации
В дополнение к вышесказанному полезные ответы, мои выводы:
Из вышесказанного видно, что “деф” - это метод (с нулевыми параметрами аргументов), которая возвращает другую функцию "и Инт => Инт” при вызове.
Преобразование методы функции хорошо описаны здесь: https://tpolecat.github.io/2014/06/09/methods-functions.html
кроме того, Валь-это оценка стоимости. Что означает, что правая часть выражения вычисляется при определении. Где Дэф-оценка имя. Он не будет оценивать, пока он's используемый.