Scala'da a var
ve val
tanım arasındaki fark nedir ve neden dilin ikisine de ihtiyacı vardır? Neden val
bir var
ve daha fazlasının seçimini yapasınız ki?
Scala'da a var
ve val
tanım arasındaki fark nedir ve neden dilin ikisine de ihtiyacı vardır? Neden val
bir var
ve daha fazlasının seçimini yapasınız ki?
Yanıtlar:
Diğerlerinin söylediği gibi, bir nesneye atanan nesne val
değiştirilemez ve bir kutuya atanan nesne değiştirilemez var
. Ancak, söz konusu nesnenin dahili durumu değiştirilebilir. Örneğin:
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.
}
}
Dolayısıyla, atanan nesneyi x
değiştiremesek de, o nesnenin durumunu değiştirebiliriz. Bununla birlikte, kökünde bir var
.
Şimdi, değişmezlik birçok nedenden dolayı iyi bir şeydir. İlk olarak, bir nesne dahili durumu değiştirmezse, kodunuzun başka bir kısmı onu değiştiriyorsa endişelenmenize gerek yoktur. Örneğin:
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")
Bu, çok iş parçacıklı sistemlerde özellikle önemli hale gelir. Çok iş parçacıklı bir sistemde aşağıdakiler olabilir:
x = new B(1)
f(x)
if (x.value.value == 1) {
print(x.value.value) // Can be different than 1!
}
Eğer kullanırsanız val
münhasıran ve sadece iletmenin veri yapıları (yani, önlemek diziler, her şeyi kullanmak scala.collection.mutable
vb), bu olmayacak emin olabilirsiniz. Yani, bazı kodlar, belki de bir çerçeve bile, yansıma hileleri yapmadıkça - yansıma ne yazık ki "değişmez" değerleri değiştirebilir.
Bu bir sebep, ama bunun başka bir nedeni daha var. Kullandığınızda var
, bunu var
birden fazla amaç için yeniden kullanmaya cazip gelebilirsiniz . Bunun bazı sorunları var:
Basitçe söylemek gerekirse, kullanmak val
daha güvenlidir ve daha okunabilir koda yol açar.
O zaman diğer yöne gidebiliriz. Bu val
daha iyi ise, neden var
hiç var ? Bazı diller bu rotayı izledi, ancak değişebilirliğin performansı arttırdığı durumlar var.
Örneğin, değişmez bir şey alın Queue
. İçinde ya enqueue
da dequeue
içinde bir şey olduğunda, yeni bir Queue
nesne alırsın . O zaman, içindeki tüm öğeleri işlemeye ne dersiniz?
Bunu bir örnekle ele alacağım. Diyelim ki bir rakam kuyruğunuz var ve bunlardan bir sayı oluşturmak istiyorsunuz. Örneğin, bu sırayla 2, 1, 3 ile bir kuyruğum varsa, 213 sayısını geri almak istiyorum. Önce bir ile çözelim mutable.Queue
:
def toNum(q: scala.collection.mutable.Queue[Int]) = {
var num = 0
while (!q.isEmpty) {
num *= 10
num += q.dequeue
}
num
}
Bu kod hızlı ve anlaşılması kolaydır. Ana dezavantajı, geçen kuyruğun tarafından değiştirilmesidir toNum
, bu nedenle önceden bir kopyasını oluşturmanız gerekir. Bu, değişmezliğin sizi özgür bıraktığı bir tür nesne yönetimi.
Şimdi bunu bir şuna çevirelim 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
Önceki örnekte olduğu gibi, bazı değişkenleri takip etmek için tekrar kullanamadığım için özyinelemeye başvurmam gerekiyor. Bu durumda, oldukça iyi bir performansa sahip bir kuyruk özyineleme. Ancak bu her zaman böyle değildir: bazen sadece iyi (okunabilir, basit) kuyruk özyineleme çözümü yoktur.
Ancak, bir immutable.Queue
ve var
aynı anda kullanmak için bu kodu yeniden yazabilirsiniz unutmayın ! Örneğin:
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
}
Bu kod hala etkilidir, özyineleme gerektirmez ve aramadan önce sıranızın bir kopyasını oluşturup oluşturmama konusunda endişelenmenize gerek yoktur toNum
. Doğal olarak, değişkenleri başka amaçlarla yeniden kullanmaktan kaçındım ve bu fonksiyonun dışındaki hiçbir kod onları görmüyor, bu yüzden değerleri açıkça bir satırdan diğerine değişme konusunda endişelenmem gerekmiyor.
Scala, programcı en iyi çözüm olduğunu düşünürse, programcının bunu yapmasına izin vermeyi tercih etti. Diğer diller bu kodu zorlaştırmayı seçmiştir. Scala'nın (ve yaygın olarak değiştirilebilen herhangi bir dilin) ödediği fiyat, derleyicinin kodu başka türlü olabildiğince optimize etmede çok fazla boşluğa sahip olmamasıdır. Java'nın cevabı, kodu çalışma zamanı profiline göre optimize etmektir. Her iki tarafın artıları ve eksileri hakkında devam edebiliriz.
Şahsen, Scala şimdilik doğru dengeye ulaşıyor. Şimdiye kadar mükemmel değil. Her iki düşünüyorum Clojure ve Haskell Scala tarafından benimsenen değil çok ilginç fikirleri vardır, ancak Scala da kendi güçlü yanları vardır. Gelecekte ne olacağını göreceğiz.
q
. Bu nesneye yapılan başvurunun yığınını değil yığınını kopyalar . Performansa gelince, neden bahsettiğiniz "o" hakkında daha net olmanız gerekir.
(x::xs).drop(1)
tam olarak xs
, bir "kopyası" değil xs
) buradan anlayabiliyorum bağlantı . tnx!
qr
değişmez bir kuyruk olduğunu ifade her zaman qr.dequeue
denir yapar bir new Queue
(<bkz github.com/scala/scala/blob/2.13.x/src/library/scala/collection/... ).
val
nihai, yani ayarlanamaz. Java'da düşünün final
.
val
değişkenler değişmezdir, ancak referans aldıkları nesnelerin olması gerekmez. Stefan'ın yayınladığı bağlantıya göre: "Burada ad referansı farklı bir Diziyi işaret edecek şekilde değiştirilemez, ancak dizinin kendisi değiştirilebilir. Başka bir deyişle dizinin içeriği / öğeleri değiştirilebilir." Yani final
Java'da nasıl çalışıyor.
+=
olarak tanımlanan mutabled bir hashmap çağırabilirim val
-tam olarak nasıl final
java çalışır inanıyorum
Basit bir ifadeyle:
var = var iable
val = v alınabilir + fin al
Aradaki fark, var
a'nın yeniden atanabilmesi, ancak a'nın atanamamasıdır val
. Değişebilirlik ya da gerçekte atanmış olan herhangi bir şey, bir yan konudur:
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.
Buna karşılık:
val n = immutable.Set("London", "Paris")
n = immutable.Set("New York") //Will not compile as n is a val.
Ve dolayısıyla:
val n = mutable.Set("London", "Paris")
n = mutable.Set("New York") //Will not compile, even though the type of n is mutable.
Bir veri yapısı oluşturuyorsanız ve tüm alanları val
s ise, bu durumda veri yapısı değişmez, çünkü durumu değişemez.
val
"Değişmez", değişmez var
anlamına gelir.
C ++ açısından düşünmek,
val x: T
sabit göstergeden sabit olmayan verilere benzer
T* const x;
süre
var x: T
sabit olmayan göstergeye sabit olmayan göstergeye benzer
T* x;
Kayırarak val
üzerinde var
onun doğruluğu, eşzamanlılık ve anlaşılabilirliğini kolaylaştırabilir kod temeli değişmezlik arttırır.
Sabit olmayan verilere sabit bir işaretçi olmanın anlamını anlamak için aşağıdaki Scala snippet'ini göz önünde bulundurun:
val m = scala.collection.mutable.Map(1 -> "picard")
m // res0: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard)
Burada "işaretçi" val m
sabittir, bu yüzden böyle bir şeye işaret etmek için yeniden atayamayız
m = n // error: reassignment to val
ancak buna m
benzeyen sabit olmayan verilerin kendisini gerçekten değiştirebiliriz
m.put(2, "worf")
m // res1: scala.collection.mutable.Map[Int,String] = HashMap(1 -> picard, 2 -> worf)
"val değişmez anlamına gelir ve var değişebilir anlamına gelir."
Paraphrase için, "val değer anlamına gelir ve var değişken anlamına gelir".
Hesaplamada son derece önemli olan bir ayrım (çünkü bu iki kavram, programlamanın neyle ilgili olduğunu özünde tanımlar) ve OO neredeyse tamamen bulanıklaşmayı başarmıştır, çünkü OO'da tek aksiyom "her şey bir nesne". Ve sonuç olarak, bu günlerde birçok programcı anlama / takdir etme / tanıma eğiliminde değil, çünkü sadece “OO yolunu düşünmek” için beyinleri yıkandı. Genellikle değişken / değişken nesnelerin her yerde olduğu gibi kullanılmasına yol açar , değer / değişmez nesneler genellikle daha iyi olabilirdi / olurdu.
val değişmez anlamına gelir ve var değişebilir anlamına gelir
val
java programlama dili final
anahtar dünyası veya c ++ dil const
anahtarı dünyası olarak düşünebilirsiniz 。
Val
final anlamına gelir , olamaz yeniden
Oysa Var
edilebilir sonradan yeniden .
Adı kadar basit.
var değişebileceği anlamına gelir
val değişmez anlamına gelir
Val - değerleri yazılan depolama sabitleridir. Oluşturulduktan sonra değeri yeniden atanamaz. val anahtar kelimesi ile yeni bir değer tanımlanabilir.
Örneğin. val x: Int = 5
Burada tip isteğe bağlıdır çünkü scala onu atanan değerden çıkarabilir.
Var - değişkenler, bellek alanı ayrıldığı sürece tekrar değerler atanabilecek tipte depolama birimleridir.
Örneğin. var x: Int = 5
Her iki depolama biriminde saklanan veriler, artık gerekli olmadığında JVM tarafından otomatik olarak ayrılır.
Skala değerlerinde kararlılık nedeniyle değişkenler tercih edilir, bunlar koda özellikle eşzamanlı ve çok iş parçacıklı kodlar getirir.
Birçoğu Val ve var arasındaki farkı zaten yanıtladı . Ancak dikkat edilmesi gereken bir nokta, val'in tam olarak nihai anahtar kelime gibi olmadığıdır .
Özyineleme kullanarak val değerini değiştirebiliriz, ancak final değerini asla değiştiremeyiz. Final Val'den daha sabittir.
def factorial(num: Int): Int = {
if(num == 0) 1
else factorial(num - 1) * num
}
Yöntem parametreleri varsayılan olarak val'dir ve her çağrı değerinde değiştirilir.
var qr = q
kopyasını çıkarıyor muq
?