Яка різниця між a varта valвизначенням у Scala і чому мова потрібна обом? Чому б ви вибрали valнад varі навпаки?
Яка різниця між a 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)
}
Тому що я не можу повторно використовувати якусь змінну, щоб відстежувати свою num , як у попередньому прикладі, мені потрібно вдатися до рекурсії. У цьому випадку це хвоста-рекурсія, яка має досить хороші показники. Але це не завжди так: іноді просто немає хорошого (читабельного, простого) рішення для рекурсії хвоста.
Однак зауважте, що я можу переписати цей код, щоб одночасно використовувати immutable.Queueі a 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 (і будь-яка мова з широкомасштабною модифікацією) платить за те, що компілятор не має стільки свободи в оптимізації коду, як міг би інакше. Відповідь Java на це - оптимізація коду на основі профілю виконання. Ми можемо продовжувати питання щодо плюсів і мінусів для кожної сторони.
Особисто я вважаю, що Скала зараз справляє правильний баланс. Це далеко не ідеально. Я думаю, що і Клуджуре, і Хаскелл мають дуже цікаві поняття, не прийняті Скалою, але і у Скали є свої сильні сторони. Ми побачимо, що з’явиться в майбутньому.
q. Це робить копію - на стеку, а не на купі - посилання на цей об'єкт. Що стосується продуктивності, то вам доведеться чіткіше зрозуміти, про яке "це" ви говорите.
(x::xs).drop(1)це точно xs, а не "копія" xs) звідси посилання, яке я міг зрозуміти. tnx!
qrє незмінною чергою, кожен раз, коли qr.dequeueвикликається вираз , він робить new Queue(див. < Github.com/scala/scala/blob/2.13.x/src/library/scala/collection/… ).
valє остаточним, тобто не може бути встановлений. Думай finalв яві.
val змінні незмінні, але об'єкти, на які вони посилаються, не повинні бути. За посиланням Стефана, розміщеним: "Тут посилання на імена неможливо змінити, щоб вказати на інший масив, але сам масив можна змінити. Іншими словами, вміст / елементи масиву можуть бути змінені." Так це, як finalпрацює на Java.
+=на мутабельну хешмап, визначену як valпросто чудову - я вважаю, як саме вона finalпрацює в Java
Простими словами:
var = var iable
val = v ariable + fin al
Різниця полягає в тому, що 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.
Якщо ви будуєте структуру даних, і всі її поля є vals, то ця структура даних є незмінною, оскільки її стан не може змінюватися.
valозначає незмінний і varозначає змінний.
Думаючи з точки зору C ++,
val x: T
є аналогом постійного вказівника на непостійні дані
T* const x;
поки
var x: T
є аналогом непостійного покажчика непостійним даним
T* x;
Улюблений valпонадvar підвищує незмінність кодової бази, що може полегшити її правильність, одночасність та зрозумілість.
Для розуміння сенсу постійного вказівника на незмінні дані розглянемо наступний фрагмент Scala:
val m = scala.collection.mutable.Map(1 -> "picard")
m // res0: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard)
Тут "покажчик" val m є постійним, тому ми не можемо повторно призначити його, щоб вказати на щось інше, як так
m = n // error: reassignment to val
однак ми можемо дійсно змінити самі постійні дані, які mвказують на подібне
m.put(2, "worf")
m // res1: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard, 2 -> worf)
"val означає незмінний, а var означає змінний."
Якщо перефразовувати, "val означає значення, а var означає змінну".
Відмінність, яка виявляється надзвичайно важливою в обчислювальних технологіях (адже ці два поняття визначають саму суть того, в чому полягає програмування), і що OO вдалося розмити майже повністю, тому що в ОО єдиною аксіомою є те, що "все є об’єкт ". І це, як наслідок, багато програмістів в наші дні, як правило, не розуміють / оцінюють / не визнають, тому що їм промили мозок виключно "мислячи шлях OO". Часто ведучи до змінних / змінних об'єктів, що використовуються, як і скрізь , коли значення / незмінні об'єкти могли / часто були б кращими.
val означає незмінний, а var означає змінний
ви можете мислити valяк finalключовий світ мови програмування java або світ ключових мов c ++ const。
Valозначає його остаточний , не може бути перепризначений
Тоді як Varможна перепризначити пізніше .
Це так просто, як його називають.
var означає, що вона може змінюватися
val означає незмінний
Значення Val - введені константи зберігання. Після створення його значення не можна перепризначити. нове значення можна визначити за допомогою ключового слова val.
напр. val x: Int = 5
Тут тип є необов’язковим, оскільки scala може визначити його із призначеного значення.
Var - змінні - це типові одиниці зберігання, яким можна знову присвоїти значення, доки зарезервовано простір пам'яті.
напр. var x: Int = 5
Дані, що зберігаються в обох блоках зберігання, автоматично розподіляються JVM після того, як вони більше не потрібні.
У масштабі масштабів перевагу надають перевагам змінним через стабільність, що приводить до коду, особливо у одночасному та багатопотоковому коді.
Хоча багато хто вже відповіли на різницю між Вал та вар . Але слід зазначити, що val не зовсім як фінал ключове слово.
Ми можемо змінити значення val за допомогою рекурсії, але ми ніколи не можемо змінити значення остаточного. Фінал більш постійний, ніж Вал.
def factorial(num: Int): Int = {
if(num == 0) 1
else factorial(num - 1) * num
}
Параметри методу за замовчуванням знаходяться за вартістю і при кожному значенні виклику змінюється.
var qr = qробить копіюq?