Skalada def, val ve var kullanımı


158
class Person(val name:String,var age:Int )
def person = new Person("Kumar",12)
person.age = 20
println(person.age)

Bu kod satırları başarılı bir şekilde yürütülmesine 12rağmen person.age=20. Bunun, def kullandığım için olduğunu fark ettim def person = new Person("Kumar",12). Var veya val kullanırsam çıkış olur 20. Ben varsayılan varsayılan scala val olduğunu anlıyorum. Bu:

def age = 30
age = 45

... varsayılan olarak bir val olduğu için bir derleme hatası verir. Yukarıdaki ilk satır kümesi neden düzgün çalışmıyor ve yine de hata yapmıyor?

Yanıtlar:


254

Scala'da bir şeyleri tanımlamanın üç yolu vardır:

  • defbir yöntem tanımlar
  • valsabit bir değer tanımlar (değiştirilemez)
  • varBir değişkeni tanımlar (değiştirilebilir)

Kodunuza bakın:

def person = new Person("Kumar",12)

Bu, yeni bir yöntem tanımlar person. Bu yöntemi sadece ()parametresiz yöntem olarak tanımlandığından çağırabilirsiniz . Boş-paren yöntemi için, bunu '()' ile veya '()' olmadan arayabilirsiniz. Sadece yazarsanız:

person

o zaman bu yöntemi çağırırsınız (ve dönüş değerini atamazsanız, sadece silinir). Bu kod satırında:

person.age = 20

ne olacağı, ilk önce personyöntemi çağırmanız ve dönüş değerinde (sınıf örneği Person) ageüye değişkenini değiştirmenizdir .

Ve son satır:

println(person.age)

Burada yine personsınıfın yeni bir örneğini döndüren yöntemi çağırıyorsunuz Person( age12 olarak ayarlanmış). Şununla aynı:

println(person().age)

27
Bir şeyleri karıştırmak için, a'nın dahili durumu valdeğiştirilebilir, ancak val tarafından atıfta bulunulan nesne değiştirilemez. A valsabit değildir.
pferrel

5
Daha fazla şey karıştırmak için, val (ve belki de var, ben denemedim) bir işlevi tanımlamak için kullanılabilir. Bir işlevi / yöntemi tanımlamak için def kullanıldığında, def'nin gövdesi her çağrıldığında değerlendirilir. Val kullanılırken sadece tanım noktasında değerlendirilir. Bkz. Stackoverflow.com/questions/18887264/…
melston

1
@melston Evet, ancak yöntem ve işlev de aynı şey değil .
Jesper

3
daha da karmaşıklaşmak için, def bir sınıfın üye değişkenlerini tanımlamak için de kullanılabilir.
Peiti Li

2
@pferrel gerçekten kafa karıştırıcı değil. Java'nın finalinde olduğu gibi. Bir işaretleyebilirsiniz Listolarak final, ancak içeriğini değiştirebilir.
jFrenetic

100

Scala'da def , val ve var arasındaki ayrımla başlıyorum .

  • def - tembel olarak değerlendirilen sağ taraf içeriği için değişmez bir etiket tanımlar - isme göre değerlendirir.

  • val - sağ taraftaki içerik için hevesle / hemen değerlendirilen - değere göre değerlendirilen değişmez bir etiket tanımlar .

  • var - başlangıçta değerlendirilen sağ taraf içeriğine ayarlanan değişken bir değişkeni tanımlar .

Örnek, def

scala> def something = 2 + 3 * 4 
something: Int
scala> something  // now it's evaluated, lazily upon usage
res30: Int = 14

Örnek, val

scala> val somethingelse = 2 + 3 * 5 // it's evaluated, eagerly upon definition
somethingelse: Int = 17

Örnek, var

scala> var aVariable = 2 * 3
aVariable: Int = 6

scala> aVariable = 5
aVariable: Int = 5

Yukarıdakilere göre, def ve val'dan etiketler yeniden atanamaz ve herhangi bir deneme durumunda aşağıdaki gibi bir hata ortaya çıkar:

scala> something = 5 * 6
<console>:8: error: value something_= is not a member of object $iw
       something = 5 * 6
       ^

Sınıf şu şekilde tanımlandığında:

scala> class Person(val name: String, var age: Int)
defined class Person

ve sonra aşağıdakilerle somutlaştırılır:

scala> def personA = new Person("Tim", 25)
personA: Person

Bir değişmez etiket Kişinin bu özel örneği (yani 'persona') oluşturulur. Değişken 'yaş' alanının değiştirilmesi gerektiğinde, bu girişim başarısız olur:

scala> personA.age = 44
personA.age: Int = 25

beklendiği gibi, 'yaş' değiştirilemez bir etiketin parçasıdır. Bunun üzerinde çalışmanın doğru yolu, aşağıdaki örnekte olduğu gibi değiştirilebilir bir değişken kullanmaktır:

scala> var personB = new Person("Matt", 36)
personB: Person = Person@59cd11fe

scala> personB.age = 44
personB.age: Int = 44    // value re-assigned, as expected

açık bir şekilde, değişken değişken referansından (yani 'personB') sınıf değişebilen 'yaş' alanını değiştirmek mümkündür.

Yine de her şeyin yukarıda belirtilen farktan geldiğini, herhangi bir Scala programcısını akılda tutması gerektiğini vurguluyorum.


Yukarıdaki açıklamanın doğru olduğunu düşünmüyorum. Diğer cevaplara bakın.
Per Mildner

@PerMildner Yukarıdaki cevapta neyin yanlış olduğunu açıklayabilir misiniz?
Syed Souban

Orijinal şikayetimin ne olduğunu hatırlamıyorum. Bununla birlikte, cevabın son kısmı, hakkında personAet al. görünüyor. Modifiye İster ageüye işleri veya olmasın kullanmak ister bağımsızdır def personAya var personB. Aradaki fark, ilk değerlendirmenizden dönen-durumunu def personAdeğiştirmenizdir . Bu örnek olan modifiye, ancak bu kez daha değerlendirmek, döndürülen ne değildir . Bunun yerine, ikinci kez etkili bir şekilde yapıyorsunuz . PersonpersonApersonApersonA.agenew Person("Tim",25).age
Per Mildner

29

İle

def person = new Person("Kumar", 12) 

her zaman "Kumar" adında ve 12 yaşında yeni bir Person örneği döndüren bir işlev / tembel değişken tanımlıyorsunuz. Bu tamamen geçerlidir ve derleyicinin şikayet etmek için bir nedeni yoktur. Person.age çağrıldığında, bu yeni oluşturulan Person örneğinin yaşı her zaman 12 olur.

Yazarken

person.age = 45

Person sınıfındaki age özelliğine, yaş olarak bildirildiğinden beri geçerli olan yeni bir değer atarsınız var. Derleyici, aşağıdaki persongibi yeni bir Person nesnesiyle yeniden atamaya çalışırsanız şikayet edecektir

person = new Person("Steve", 13)  // Error

Evet. Bu nokta, kolayca hashCode yöntemi çağrılarak gösterilebilir Persona'yı
Nilanjan Sarkar

26

Başka bir bakış açısı sağlamak için, Scala'daki "def" her kullanıldığında değerlendirilecek bir şey anlamına gelirken, val hemen ve sadece bir kez değerlendirilen bir şeydir . Burada ifade, def person = new Person("Kumar",12)"kişi" yi her kullandığımızda bir new Person("Kumar",12)çağrı alacağımızı gerektirir. Bu nedenle, iki "person.age" nin birbiriyle ilişkili olmaması doğaldır.

Scala'yı böyle anlıyorum (muhtemelen daha "işlevsel" bir şekilde). Emin değilim

def defines a method
val defines a fixed value (which cannot be modified)
var defines a variable (which can be modified)

gerçekten Scala'nın ne demek istediği. En azından böyle düşünmeyi gerçekten sevmiyorum ...


20

Kintaro'nun söylediği gibi, kişi bir yöntemdir (def nedeniyle) ve her zaman yeni bir Kişi örneği döndürür. Bildiğiniz gibi, yöntemi bir var veya val olarak değiştirirseniz işe yarayacaktır:

val person = new Person("Kumar",12)

Başka bir olasılık:

def person = new Person("Kumar",12)
val p = person
p.age=20
println(p.age)

Ancak, person.age=20kodunuzda, yöntemden bir Personörnek alırken personve bu örnekte, a'nın değerini değiştirmenize izin verilir var. Sorun şu ki, bu satırdan sonra o örneğe artık başvurmuyorsunuz (her çağrı personyeni bir örnek üreteceğinden).

Bu özel bir şey değil, Java'da tam olarak aynı davranışa sahip olacaksınız:

class Person{ 
   public int age; 
   private String name;
   public Person(String name; int age) {
      this.name = name;  
      this.age = age;
   }
   public String name(){ return name; }
}

public Person person() { 
  return new Person("Kumar", 12); 
}

person().age = 20;
System.out.println(person().age); //--> 12

8

Bunu alalım:

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
person.age=20
println(person.age)

ve eşdeğer kodla yeniden yaz

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
(new Person("Kumar", 12)).age_=(20)
println((new Person("Kumar", 12)).age)

Bakın, defbir yöntem. Her çağrıldığında yürütülür ve her geri döndüğünde (a) new Person("Kumar", 12). Ve bunlar "atama" da bir hata değildir, çünkü bu gerçekten bir atama değildir, sadece age_=yönteme bir çağrıdır (tarafından sağlanır var).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.