изменяемые по сравнению с неизменяемыми в Scala

Существуют ли в Scala рекомендации относительно того, когда использовать val с изменяемой коллекцией по сравнению с использованием var с неизменяемой коллекцией? Или вы действительно должны стремиться к Вэл с неизменной коллекцией?

Тот факт, что есть оба типа коллекций, дает мне большой выбор, и часто я не делаю знать, как сделать этот выбор.

 Luigi Plinge08 июл. 2012 г., 23:22
Смотри напримерstackoverflow.com/questions/10999024/…

Ответы на вопрос(5)

Лучший способ ответить на этот вопрос - на примере. Предположим, у нас есть какой-то процесс, просто собирающий числа по какой-то причине. Мы хотим записать эти номера и отправим коллекциюanother Процесс, чтобы сделать это.

Конечно, мы все еще собираем числа после того, как отправим коллекцию в регистратор. И скажем, есть некоторые издержки в процессе регистрации, которые задерживают фактическую регистрацию. Надеюсь, вы увидите, куда это идет.

Если мы храним эту коллекцию в изменчивомval(изменяемый, потому что мы постоянно добавляем к нему), это означает, что процесс, выполняющий регистрацию, будет смотреть наsame object это все еще обновляется нашим процессом сбора. Эта коллекция может быть обновлена в любое время, и поэтому, когда пришло время регистрировать, мы, возможно, не регистрируем отправленную коллекцию.

Если мы используем неизменныйvar, мы отправляем неизменную структуру данных в регистратор. Когда мы добавим больше номеров в нашу коллекцию, мы будемreplacing нашvar сnew immutable data structure, Это не означает, что коллекция, отправленная регистратору, заменена! Он по-прежнему ссылается на коллекцию, которую он отправил. Таким образом, наш регистратор действительно зарегистрирует полученную коллекцию.

 23 янв. 2014 г., 18:54
Here это пример (этого примера !!)

Я думаю, что примеры в этом посте будут проливать больше света, так как вопрос о том, какую комбинацию использовать, становится еще более важным в сценариях параллелизма:Важность неизменности для параллелизма, И пока мы на это обращаем внимание, обратите внимание на предпочтительное использование синхронизированных по сравнению с @volatile и чем-то вроде AtomicReference:три инструмента

 28 сент. 2017 г., 23:59
@EdgeCaseBerg Но вы не можете повторить поведение, с которым я сталкиваюсьArrayBuffer, используяVector, Вопрос OP является широким, но они искали предложения о том, когда использовать, который, поэтому я считаю, что мой ответ полезен, потому что он иллюстрирует опасности передачи изменяемой коллекции (факт, которыйval не помогает);immutable var безопаснее, чемmutable val.
 27 сент. 2017 г., 19:38
@EdgeCaseBerg, я намеренно использую вектор во втором примере, потому что я пытаюсь показать поведение первого примера.mutable val невозможно сimmutable var, Что здесь неверного?
 27 сент. 2017 г., 19:25
Это неверно Причина, по которой вы получили эту ошибку, заключается в том, что вы использовали Vector во втором примере, который по умолчанию является неизменяемым. Если вы используете ArrayBuffer, вы увидите, что он прекрасно компилируется и делает то же самое, когда просто добавляет новый элемент и распечатывает мутированный буфер.pastebin.com/vfq7ytaD
 27 сент. 2017 г., 20:40
Вы сравниваете яблоки с апельсинами здесь. Вектор не имеет+= метод, как массив буферов. Ваши ответы подразумевают, что+= такой же какx = x + y что это не так. Ваше утверждение о том, что функциональные параметры обрабатываются как vals, является правильным, и вы получаете ошибку, о которой упоминаете, но только потому, что вы использовали=, Вы можете получить ту же ошибку с ArrayBuffer, поэтому изменчивость коллекций здесь не очень актуальна. Так что это не очень хороший ответ, потому что он не понимает, о чем говорит ОП. Хотя это хороший пример опасности передачи изменяемой коллекции, если вы этого не хотели.

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

В общем, убедитесь, что вы не путаете ссылки и объекты.vals являются неизменяемыми ссылками (постоянные указатели в C). То есть когда вы используетеval x = new MutableFoo()вы сможетеto change the object тотx указывает на, но вы не сможетеto change to which object x точки. Противоположность имеет место, если вы используетеvar x = new ImmutableFoo(), Подбирая мой первоначальный совет: если вам не нужно менять, к какому объекту относятся контрольные точки, используйтеvals.

 11 сент. 2013 г., 03:14
var immutable = something(); immutable = immutable.update(x) побеждает цель использования неизменной коллекции. Вы уже отказались от ссылочной прозрачности, и вы обычно можете получить тот же эффект от изменяемой коллекции с большей временной сложностью. Из четырех возможностей (val а такжеvarизменчивый и неизменный), этот имеет наименьший смысл. Я часто используюval mutable.
 19 мар. 2014 г., 08:23
@ErikAllik Я бы не сказал, что устаревшие данные сами по себе желательны, но я согласен с тем, что они могут быть совершенно нормальными, в зависимости от гарантий, которые вы хотите / должны дать своим клиентам. Или у вас есть пример, где единственный факт чтения устаревших данных на самом деле является преимуществом? Я не имею в виду последствия принятия устаревших данных, которые могут быть лучшей производительностью или более простым API.
 11 мар. 2014 г., 18:00
@MalteSchwerhoff: «устаревшие данные»; на самом деле желательно, в зависимости от того, как вы разработали свою программу, если согласованность имеет решающее значение; это, например, один из основных принципов работы параллелизма в Clojure.
 02 дек. 2013 г., 14:10
@JimPivarski Я не согласен, как и другие, см. Ответ Даниила и комментарий Питера. Если вам необходимо обновить структуру данных, то использование неизменяемого var вместо изменяемого val имеет то преимущество, что вы можете просочиться в ссылки на структуру без риска, что она будет изменена другими так, что нарушит ваши локальные предположения. Недостаток для этих «других» в том, что они могут читать устаревшие данные.
 02 дек. 2013 г., 19:11
Я передумал и согласен с вами (я оставляю свой оригинальный комментарий к истории). С тех пор я использовал это, особенно вvar list: List[X] = Nil; list = item :: list; ... и я забыл, что когда-то писал по-другому.

var immutable противval mutable

Помимо множества отличных ответов на этот вопрос. Вот простой пример, который иллюстрирует потенциальную опасностьval mutable:

Изменяемые объекты могут быть изменены внутри методов, которые принимают их в качестве параметров, в то время как переназначение запрещено.

import scala.collection.mutable.ArrayBuffer

object MyObject {
    def main(args: Array[String]) {

        val a = ArrayBuffer(1,2,3,4)
        silly(a)
        println(a) // a has been modified here
    }

    def silly(a: ArrayBuffer[Int]): Unit = {
        a += 10
        println(s"length: ${a.length}")
    }
}

Результат:

length: 5
ArrayBuffer(1, 2, 3, 4, 10)

Нечто подобное не может случиться сvar immutableпотому что переназначение не допускается:

object MyObject {
    def main(args: Array[String]) {
        var v = Vector(1,2,3,4)
        silly(v)
        println(v)
    }

    def silly(v: Vector[Int]): Unit = {
        v = v :+ 10 // This line is not valid
        println(s"length of v: ${v.length}")
    }
}

Результаты в:

error: reassignment to val

Поскольку параметры функции рассматриваются какval это переназначение не допускается.

 27 сент. 2017 г., 19:38
@EdgeCaseBerg, я намеренно использую вектор во втором примере, потому что я пытаюсь показать поведение первого примера.mutable val невозможно сimmutable var, Что здесь неверного?
 28 сент. 2017 г., 23:59
@EdgeCaseBerg Но вы не можете повторить поведение, с которым я сталкиваюсьArrayBuffer, используяVector, Вопрос OP является широким, но они искали предложения о том, когда использовать, который, поэтому я считаю, что мой ответ полезен, потому что он иллюстрирует опасности передачи изменяемой коллекции (факт, которыйval не помогает);immutable var безопаснее, чемmutable val.
 27 сент. 2017 г., 20:40
Вы сравниваете яблоки с апельсинами здесь. Вектор не имеет+= метод, как массив буферов. Ваши ответы подразумевают, что+= такой же какx = x + y что это не так. Ваше утверждение о том, что функциональные параметры обрабатываются как vals, является правильным, и вы получаете ошибку, о которой упоминаете, но только потому, что вы использовали=, Вы можете получить ту же ошибку с ArrayBuffer, поэтому изменчивость коллекций здесь не очень актуальна. Так что это не очень хороший ответ, потому что он не понимает, о чем говорит ОП. Хотя это хороший пример опасности передачи изменяемой коллекции, если вы этого не хотели.
 27 сент. 2017 г., 19:25
Это неверно Причина, по которой вы получили эту ошибку, заключается в том, что вы использовали Vector во втором примере, который по умолчанию является неизменяемым. Если вы используете ArrayBuffer, вы увидите, что он прекрасно компилируется и делает то же самое, когда просто добавляет новый элемент и распечатывает мутированный буфер.pastebin.com/vfq7ytaD
Решение Вопроса

Это довольно распространенный вопрос. Трудно найти дубликаты.

Вы должны стремиться кreferential transparency, Это означает, что, если у меня есть выражение «e», я мог бы сделатьval x = eи заменитьe сx, Это свойство, которое нарушает изменчивость. Всякий раз, когда вам нужно принять проектное решение, максимально увеличить ссылочную прозрачность.

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

С другой стороны, изменчивая коллекция имеетpotential убежать, даже если это не так. При изменении кода вы можете захотеть передать его другим методам или вернуть. Это та вещь, которая нарушает ссылочную прозрачность.

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

 15 янв. 2014 г., 00:52
Имейте в виду, что вы все еще можете закрыть (как при утечке «побочную» «функцию», которая может ее изменить) на локальный изменяемыйvar, Еще одна приятная особенность использования неизменяемых коллекций заключается в том, что вы можете эффективно хранить старые копии, даже еслиvar мутирует.
 03 окт. 2015 г., 20:30
TL; Dr: предпочитаюvar x: Set[Int] over val x: mutable.Set[Int] так как если вы пройдетеx в какой-то другой функции, в первом случае вы уверены, что эта функция не может мутироватьx для тебя.
 09 июл. 2012 г., 08:34
Хорошая, новая большая картина в моей голове: Предпочитаюimmutable val надimmutable var надmutable val надmutable var, Особенноimmutable var надmutable val!

Ваш ответ на вопрос