В Scala существует несколько способов обозначения значений и методов, так же как и обращения к ним, и сразу понять их может быть немного затруднительно, так давайте же разберёмся вместе?
Начнём с самого простого - val и var, в чём различие между ними? Поможет понять "продолжение слова", VALue и VARiable - как не трудно после этого догадаться, первый - как значение - неизменный, а второй - изменяемый. По-хорошему старайтесь избегать использования var, ведь в функциональном подходе мутабельность(изменяемость) является отрицательным качеством, по многим причинам, но не об этом сегодня.
Теперь давайте посмотрим на def и val, тут уже может быть не столь ясно. Чего же тут сложного, def - метод, val - значение, - скажете Вы. Так то оно так, но понимание скрыто чуть глубже, посмотрим на наглядный пример:
val func : Int => String = "Number is " + _.toString
def func2(a:Int) = "Number is " + a.toString
Вот два "метода", скажем так, которые делают абсолютно одно и то же, даже вызов будет одинаков: func(2) или func2(2) - при выводе вы получите одно и то же, если не верите, то можете проверить. Так в чём же разница? Давайте добавим в тело методов небольшой сайд-эффект, и обратимся к ним по 2 раза?
val func : Int => String = {
println("initialized func")
"Number is " + _.toString
}
def func2(a:Int) = {
println("initialized func2")
"Number is " + a.toString
}
println(func(2))
println(func(3))
println(func2(2))
println(func2(3))
Тут вы будете немного удивленны, на экране мы увидим следующее:
initialized func
Number is 2
Number is 3
initialized func2
Number is 2
initialized func2
Number is 3
Дело в том, что к def при обращении мы "запускаем" метод полностью каждый раз, а к val - только единожды, и далее храним значение функции, и последующего высвобождения сайд-эффектов не происходит!
Точно такой же логикой обладают обращение по имени и по значению:
def func1(a: => Int) = "Number is " + a.toString
def func2(a:Int) = "Number is " + a.toString
В первом случае "а" не будет инициализирована до того момента, пока к ней не обратятся, то есть "ленивым" методом, а во втором случае - она будет инициализирована, или должна быть уже инициализирована, во время вызова метода!
Все способы обозначения и обращения имеют определённые тонкости и моменты, в которых их необходимо использовать, и понимание сути их исполнения - ключ к пониманию мест, где это стоит делать.