В чем разница между определением var и val в Scala?

В чем разница между определением var и val в Scala и зачем нужен язык? Почему вы выбрали val над var и наоборот?

Как и многие другие, объект, назначенный val не может быть заменен, а объект, назначенный var может. Однако у указанного объекта может быть изменено его внутреннее состояние. Например:

 class A(n: Int) { var value = n } class B(n: Int) { val value = new A(n) } object Test { def main(args: Array[String]) { val x = new B(5) x = new B(6) // Doesn't work, because I can't replace the object created on the line above with this new one. x.value = new A(6) // Doesn't work, because I can't replace the object assigned to B.value for a new one. x.value.value = 6 // Works, because A.value can receive a new object. } } 

Поэтому, хотя мы не можем изменить объект, назначенный на x , мы могли бы изменить состояние этого объекта. Однако в его основе существовал var .

Теперь неизменность – это хорошо по многим причинам. Во-первых, если объект не изменяет внутреннее состояние, вам не нужно беспокоиться, если какая-либо другая часть вашего кода меняет его. Например:

 x = new B(0) f(x) if (x.value.value == 0) println("f didn't do anything to x") else println("f did something to x") 

Это особенно важно для многопоточных систем. В многопоточной системе может случиться следующее:

 x = new B(1) f(x) if (x.value.value == 1) { print(x.value.value) // Can be different than 1! } 

Если вы используете исключительно val и используете только неизменяемые структуры данных (то есть избегайте массивов, все в scala.collection.mutable и т. Д.), Вы можете быть уверены, что этого не произойдет. То есть, если есть какой-то код, возможно, даже фреймворк, делающий рефлексивные трюки – размышление может изменить «неизменные» ценности, к сожалению.

Это одна из причин, но для этого есть еще одна причина. Когда вы используете var , вы можете быть соблазнены повторным использованием одного и того же var для нескольких целей. У этого есть некоторые проблемы:

  • Пользователям, читающим код, будет труднее узнать, что представляет собой значение переменной в определенной части кода.
  • Вы можете забыть повторно инициализировать переменную в некотором пути кода и в конечном итоге передать неправильные значения ниже по течению в коде.

Проще говоря, использование val более безопасно и приводит к более читаемому коду.

Тогда мы можем пойти в другом направлении. Если val это лучше, зачем вообще var ? Ну, некоторые языки сделали этот маршрут, но есть ситуации, в которых изменчивость улучшает производительность, много.

Например, возьмите неизменяемую Queue . Когда вы либо enqueue либо dequeue вещи, вы получаете новый объект Queue . Как же тогда вы собираетесь обрабатывать все предметы в нем?

Я рассмотрю это с помощью примера. Предположим, у вас есть очередь цифр, и вы хотите составить номер из них. Например, если у меня есть очередь с 2, 1, 3, в этом порядке, я хочу вернуть номер 213. Давайте сначала разрешим его с помощью mutable.Queue :

 def toNum(q: scala.collection.mutable.Queue[Int]) = { var num = 0 while (!q.isEmpty) { num *= 10 num += q.dequeue } num } 

Этот код быстро и легко понять. Его главный недостаток заключается в том, что передаваемая очередь модифицируется toNum , поэтому вам нужно сделать ее копию заранее. Это тип управления объектами, из которого неизменяемость освобождает вас.

Теперь давайте спрячем его на immutable.Queue .

 def toNum(q: scala.collection.immutable.Queue[Int]) = { def recurse(qr: scala.collection.immutable.Queue[Int], num: Int): Int = { if (qr.isEmpty) num else { val (digit, newQ) = qr.dequeue recurse(newQ, num * 10 + digit) } } recurse(q, 0) } 

Поскольку я не могу повторно использовать некоторую переменную для отслеживания моего числа, как в предыдущем примере, мне нужно прибегнуть к рекурсии. В этом случае это хвостовая recursion, которая имеет неплохую производительность. Но это не всегда так: иногда нет хорошего (читаемого, простого) решения хвостовой рекурсии.

Обратите внимание, однако, что я могу переписать этот код для использования immutable.Queue и var в одно и то же время! Например:

 def toNum(q: scala.collection.immutable.Queue[Int]) = { var qr = q var num = 0 while (!qr.isEmpty) { val (digit, newQ) = qr.dequeue num *= 10 num += digit qr = newQ } num } 

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

Scala решила позволить программисту сделать это, если программист счел это лучшим решением. Другие языки решили сделать такой код сложным. Цена Scala (и любой язык с широко распространенной изменчивостью) платит, так это то, что у компилятора не так много возможностей для оптимизации кода, как в противном случае. Ответ Java на это – оптимизация кода на основе профиля времени выполнения. Мы могли бы продолжать и обсуждать все плюсы и минусы каждой стороны.

Лично я считаю, что сейчас Scala поражает правильный баланс. Это далеко не идеальный вариант. Я думаю, что у Clojure и Haskell есть очень интересные понятия, не принятые Scala, но у Scala есть свои сильные стороны. Посмотрим, что произойдет в будущем.

val является окончательным, то есть не может быть задано. Думайте final в java.

Проще говоря:

var = var iable

val = v ariable + fin al

val означает неизменяемое, а var означает mutable.

Полное обсуждение.

Разница в том, что var может быть повторно назначен, тогда как val не может. Изменчивость или, в любом случае, то, что фактически назначено, является побочной проблемой:

 import collection.immutable import collection.mutable var m = immutable.Set("London", "Paris") m = immutable.Set("New York") //Reassignment - I have change the "value" at m. 

В то время как:

 val n = immutable.Set("London", "Paris") n = immutable.Set("New York") //Will not compile as n is a val. 

И поэтому:

 val n = mutable.Set("London", "Paris") n = mutable.Set("New York") //Will not compile, even though the type of n is mutable. 

Если вы строите структуру данных, и все ее поля являются val s, тогда эта структура данных является неизменной, поскольку ее состояние не может измениться.

Думая о С ++,

 val x: T 

аналогичен постоянному указателю на непостоянные данные

 T* const x; 

в то время как

 var x: T 

аналогичен непостоянному указателю на непостоянные данные

 T* x; 

Приоритет val над var увеличивает неизменность кодовой базы, которая может облегчить ее правильность, параллельность и понятность.

«val означает неизменяемость, а var означает изменчивость».

Перефразируя «значение val означает значение, а var означает переменную».

Различие, которое чрезвычайно важно для вычислений (поскольку эти два понятия определяют саму суть программирования), и что OO удалось полностью размыть, потому что в OO единственная аксиома заключается в том, что «все объект». И, как следствие, многие программисты в наши дни, как правило, не понимают / ценят / не признают, потому что им «промывают мозги» исключительно «мышлением OO». Часто приводя к переменным / изменяемым объектам, которые используются как везде , когда значения / неизменяемые объекты могли / часто бывали лучше.

val означает неизменное, а var означает изменчивое

вы можете думать, что в качестве ключевого мира языка программирования Java или языка c ++ language const key.

Параметр val похож на конечную переменную в Java. После инициализации значение val никогда не может быть переназначено.

Напротив, var похож на не конечную переменную в Java. На протяжении всей жизни переменная var может быть переназначена.

Это так просто, как имя.

var означает, что он может меняться

val означает неизменное

Значения Val – это типизированные константы хранения. После создания его значение не может быть повторно назначено. новое значение может быть определено с помощью ключевого слова val.

например. val x: Int = 5

Здесь тип необязателен, поскольку scala может вывести его из назначенного значения.

Var – переменные представляют собой типизированные единицы хранения, которые могут быть назначены значения снова, пока зарезервировано пространство памяти.

например. var x: Int = 5

Данные, хранящиеся в обоих единицах хранения, автоматически де-распределяются JVM, как только они больше не нужны.

В значениях scala предпочтительнее переменных из-за стабильности, которые приводят к коду, особенно в параллельном и многопоточном коде.

Хотя многие уже ответили на разницу между Val и var . Но один момент, чтобы заметить, что val не совсем как последнее ключевое слово.

Мы можем изменить значение val, используя рекурсию, но мы никогда не сможем изменить значение final. Финал более постоянный, чем Val.

 def factorial(num: Int): Int = { if(num == 0) 1 else factorial(num - 1) * num } 

Параметры метода по умолчанию имеют значение val и при каждом изменении значения вызова.

Val означает его окончательный , не может быть переназначен

В то время как Var может быть переназначен позже .

  • Отладка Scala-кода с помощью простого-build-инструмента (sbt) и IntelliJ
  • Каково ключевое слово forSome в Scala?
  • Требуется уточнение для лирических идентификаторов Scala (backticks)
  • Вызовите по имени vs call по значению в Scala, необходимо разъяснение
  • Подчеркивание в List.filter
  • Как импортировать build.gradle в IntelliJ
  • Прочитать весь файл в Scala?
  • В Scala есть оператор присваивания «=» вызов метода?
  • Как применить функцию к кортежу?
  • Как создать TypeTag вручную?
  • Оператор <: <в scala
  • Давайте будем гением компьютера.