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

Te linie kodu wyjściowego 12, mimo że person.age=20 zostało pomyślnie wykonane. Zauważyłem, że tak się dzieje, ponieważ użyłem def w def person = new Person("Kumar",12). Jeśli używam var lub val, wynikiem jest 20. Rozumiem, że domyślną wartością jest val w scala. To:Użycie def, val i var w scala

def age = 30 
age = 45 

... podaje błąd kompilacji, ponieważ jest domyślnie wartością val. Dlaczego pierwszy zestaw powyższych linii nie działa poprawnie, a jednocześnie nie powoduje błędu?

Odpowiedz

29

Z

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

definiujesz funkcję/lazy zmienną, która zawsze zwraca nową instancję osoba o nazwie „Kumar” i wieku 12. Jest to całkowicie poprawny i kompilator nie ma powodów do narzekań. Wywołanie person.age powróci wiek tej nowo utworzonej przykład osoby, która jest zawsze 12.

Pisząc

person.age = 45 

przypisać nową wartość do właściwości wiekowej w klasie Osoba, która jest ważna, ponieważ wiek jest zadeklarowany jako var. Kompilator będzie narzekać, jeśli starają się przypisać person z nowego obiektu osoba jak

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

Jak Kintaro już mówi osoba jest metoda (z powodu braków) i zawsze zwraca nową instancję osoby. Jak okazało się, że to działa, jeśli zmienić sposób do var lub Val:

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

Inną możliwością byłoby:

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

Jednak person.age=20 w kodzie jest dozwolone, jak wrócisz instancję Person z metody person, a na tym wystąpieniu można zmienić wartość var. Problem polega na tym, że po tej linii nie ma już odniesienia do tej instancji (ponieważ każde wywołanie do person spowoduje utworzenie nowej instancji).

Jest to nic specjalnego, trzeba będzie dokładnie takie samo zachowanie w Javie:

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 
+0

Ta odpowiedź jest najwyraźniejszym wyjaśnieniem. – stackoverflowuser2010

221

Istnieją trzy sposoby definiowania rzeczy w Scala:

  • def definiuje metody
  • val definiuje stałą wartość o wartości (której nie można zmienić)
  • var definiuje zmienna (które mogą być modyfikowane)

Patrząc na kodzie:

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

ten definiuje nową metodę o nazwie person. Możesz wywołać tę metodę tylko bez (), ponieważ jest ona zdefiniowana jako metoda bez parametrów. W przypadku metody pustej-paren możesz wywołać ją z lub bez '()'. Jeśli po prostu napisać:

person 

to jesteś wywołanie tej metody (a jeśli nie przypisywać wartości zwracanej, to będzie po prostu wyrzucić). W tej linii kodu:

person.age = 20 

co się dzieje, jest to, że najpierw wywołać metodę person, a na wartości zwracanej (instancją klasy Person) Zmieniasz zmienną age użytkownika.

I ostatnia linia:

println(person.age) 

Tu znów wywołując metodę person, która zwraca nową instancję klasy Person (z age zestawu do 12). Jest taki sam jak ten:

println(person().age) 
+19

Aby wprowadzić zamieszanie, można zmienić wewnętrzny stan '' 'val''', ale obiekt, do którego odwołuje się val, nie może tego zmienić. '' 'Val''' nie jest stałą. – pferrel

+3

Aby jeszcze bardziej zmylić rzeczy, val (i może var też, nie próbowałem go) może być użyty do zdefiniowania funkcji. Używając def do zdefiniowania funkcji/metody, ciało def jest oceniane za każdym razem, gdy jest wywoływane. Podczas korzystania z val jest oceniany tylko w punkcie definicji. Zobacz http://stackoverflow.com/questions/18887264/what-is-the-difference-between-def-and-val-to-define-a-function – melston

+1

@melston Tak, ale * metoda * i funkcja * * także nie są dokładnie [to samo] (http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala). – Jesper

8

Weźmy to:

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

i przepisać go z równoważnym kodem

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) 

widać, def jest metoda. Będzie wykonywany za każdym razem, gdy zostanie wywołany i za każdym razem zwróci (a) new Person("Kumar", 12). I nie jest to błąd w "zadaniu", ponieważ nie jest tak naprawdę zadaniem, ale po prostu wywołaniem metody age_= (dostarczonej przez var).

23

Aby zapewnić inną perspektywę „def” w Scala oznacza coś, co będzie być oceniane każdorazowo gdy jest używany, natomiast val jest czymś oceniano natychmiast i tylko raz. W tym przypadku wyrażenie def person = new Person("Kumar",12) powoduje, że za każdym razem, gdy użyjemy "osoby", otrzymamy wywołanie new Person("Kumar",12). Dlatego naturalne jest, że dwa "person.age" są niepowiązane.

W ten sposób rozumiem Scalę (prawdopodobnie w bardziej "funkcjonalny" sposób). Nie jestem pewien, czy naprawdę Scala zamierza jednak oznaczać. I naprawdę nie lubią myśleć w ten sposób co najmniej ...

70

zacząłbym od różnicy, jaka istnieje w Scala między def, val i var.

  • def - definiuje niezmienny etykietę na prawej bocznej zawartości, która jest leniwie ocenianego - oceniać według nazwy.

  • Val - określa niezmienny etykietę na prawej stronie zawartości, która jest chętnie/bezpośrednio oceniany - ocenia wartości.

  • var - definiuje zmienny zmienną, początkowo ustawiony na ocenianym prawej bocznej treści.

Przykład Def

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

Przykład Val

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

przykład, zmienna

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

scala> aVariable = 5 
aVariable: Int = 5 

Według wyżej, etykiety z def i val nie może być przeniesiony, a w przypadku jakiejkolwiek próby błąd jak poniżej jednego zostaną podniesione:

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

Kiedy klasa jest zdefiniowana następująco:

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

i tworzony z:

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

an niezmienna etykieta jest tworzona dla tej konkretnej instancji Osoby (tj. 'osoba'). Ilekroć „wiek” polu Zmienna musi być zmodyfikowana, taka próba nie powiedzie się:

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

zgodnie z oczekiwaniami, „wiek” jest częścią non-zmienny etykiecie.Prawidłowy sposób do pracy na tym polega na użyciu zmiennej zmienny, jak w poniższym przykładzie:

scala> var personB = new Person("Matt", 36) 
personB: Person = [email protected] 

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

jako przezroczysty, z zmienny sygnał sterujący (IE personB "), możliwe jest modyfikowanie klasę zmienne pole "wiek".

Nadal podkreślam fakt, że wszystko pochodzi od wyżej opisanej różnicy, co musi być jasne dla każdego programisty Scala.

Powiązane problemy