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

Я читаю Программу в Scala книге Scala Creator, и я немного запутался на примере Set.

Здесь это для неизменяемого набора:

var jetSet = Set("Boeing", "Airbus")
jetSet += "Lear"
println(jetSet.contains("Cessna"))

В чем смысл этого?

Множество является неизменным, но переменная jetSet является изменяемой. 1) Итак, каждый раз, когда я добавляю к набору с + =, он создает новый набор? Итак, переменная указывает на новый набор в памяти?

2) Не должно быть: val jetSet = set("cow","sheep","duck")? Почему это должно быть var? Есть ли причина использовать var для неизменяемого набора?

Ответ 1

Преимущество неизменяемых структур данных, в данном случае Set, заключается в том, что они являются постоянными. Например:

var jetSet1 = Set("Boeing", "Airbus")
val jetSet2 = jetSet1 // ... imagine jetSet2 is somewhere else in the program
jetSet1 += "Lear"
assert(!jetSet2.contains("Lear"))

Неизменяемость этих объектов Set упрощает рассуждение о программе, поскольку обновления переменной jetSet1 не имеют побочных эффектов в других частях кода (в этом случае везде, где используется jetSet2). Хотя из этого примера неясно, бывают случаи, когда удобно хранить неизменяемые значения в изменяемых ссылках var; чаще всего var будет иметь ограниченную область действия (например, локально для функции).

Неизменяемые структуры данных часто имеют умные реализации, которые являются достаточно эффективными. К сожалению, API-интерфейс Scala API недостаточно хорошо документирован в отношении производительности, но я ожидаю, что большинство операций будут примерно равны O (log N). Например, учитывая большой неизменяемый Set s, нужно иметь возможность эффективно построить s + x новый набор с дополнительным элементом. Разумеется, неизменность гарантирует, что s также сохраняется. Под капотом s и s+x будут храниться с использованием каких-то древовидных структур данных с общими компонентами.

В заголовке вашего вопроса вы также найдете советы по использованию val или var. Эмпирическое правило - использовать val всякий раз, когда вы можете удобно. Если требуется var, попробуйте как можно больше ограничить область переменных.

Ответ 2

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

Целью примера было показать, что даже если вы попытаетесь "изменить" неизменяемую коллекцию, изменения создадут новую коллекцию, а не касаются оригинальной. Если бы автор использовал val (по строкам final в Java), ему пришлось бы ввести переменную в области, чтобы сохранить новый неизменяемый набор. Я думаю, что var, вероятно, использовался, чтобы простой пример.

Ответ 3

вы не можете сделать +=, если используете val. val/var/def применяется к символу, а не к его значению/реализации попробуйте val... вы получите компиляцию error.