class Person(val name:String,var age:Int )
def person = new Person("Kumar",12)
person.age = 20
println(person.age)
Te wiersze kodu wyjściowego 12
, mimo że person.age=20
zostały pomyślnie wykonane. Okazało się, że dzieje się tak, ponieważ użyłem def w def person = new Person("Kumar",12)
. Jeśli używam var lub val, wyjście to 20
. Rozumiem, że domyślną wartością jest val w scali. To:
def age = 30
age = 45
... wyświetla błąd kompilacji, ponieważ domyślnie jest to wartość val. Dlaczego pierwszy zestaw powyższych wierszy nie działa poprawnie, a jednocześnie nie zawiera błędów?
val
można zmienić stan wewnętrzny a, ale obiekt, do którego odwołuje się wartość, nie może. Aval
nie jest stałą.List
jakofinal
, ale możesz modyfikować jego zawartość.Zacząłbym od rozróżnienia istniejącego w Scali między def , val i var .
def - definiuje niezmienną etykietę dla zawartości po prawej stronie, która jest leniwie oceniana - oceniana według nazwy.
val - definiuje niezmienną etykietę dla treści po prawej stronie, która jest chętnie / natychmiast oceniana - oceniana według wartości.
var - definiuje zmienną modyfikowalną , początkowo ustawioną na wartościowaną zawartość po prawej stronie.
Przykład, pok
Przykład, val
Przykład, var
Zgodnie z powyższym, etykiet z def i val nie można ponownie przypisać, aw przypadku jakiejkolwiek próby podniesiony zostanie błąd podobny do poniższego:
Gdy klasa jest zdefiniowana w następujący sposób:
a następnie utworzono za pomocą:
niezmienne etykieta jest tworzony dla tej instancji konkretnej osoby (czyli „Persona”). Za każdym razem, gdy zmienne pole „age” wymaga modyfikacji, taka próba kończy się niepowodzeniem:
zgodnie z oczekiwaniami „wiek” jest częścią niezmiennej etykiety. Prawidłowy sposób pracy polega na zastosowaniu zmiennej mutowalnej, jak w poniższym przykładzie:
co oczywiste, z odniesienia do zmiennej mutowalnej (tj. „personB”) można zmodyfikować pole mutable class „age”.
Podkreśliłbym jeszcze fakt, że wszystko bierze się z podanej powyżej różnicy, o której każdy programista Scala musi sobie jasno uświadomić.
źródło
personA
et al. wydaje się wyłączony. To, czy modyfikacjaage
członka działa, czy nie, jest niezależne od tego, czy używaszdef personA
lubvar personB
. Różnica polega na tym, że wdef personA
przypadku modyfikowaniaPerson
-instancji zwróconej z pierwszej ocenypersonA
. Ta instancja jest modyfikowana, ale nie jest zwracana podczas ponownej ocenypersonA
. Zamiast tego, za drugim razem robiszpersonA.age
to skutecznienew Person("Tim",25).age
.Z
definiujesz funkcję / zmienną leniwą, która zawsze zwraca nową instancję Person o nazwie „Kumar” i wieku 12. Jest to całkowicie poprawne i kompilator nie ma powodu do narzekań. Wywołanie person.age zwróci wiek nowo utworzonej instancji Person, który zawsze wynosi 12.
Podczas pisania
przypisujesz nową wartość właściwości age w klasie Person, która obowiązuje od momentu zadeklarowania wieku jako
var
. Kompilator będzie narzekał, jeśli spróbujesz ponownie przypisaćperson
nowy obiekt Person, taki jakźródło
Aby zapewnić inną perspektywę, „def” w Scali oznacza coś, co będzie oceniane za każdym razem, gdy zostanie użyte, podczas gdy val jest czymś, co jest oceniane natychmiast i tylko raz . Tutaj wyrażenie
def person = new Person("Kumar",12)
oznacza, że za każdym razem, gdy użyjemy słowa „osoba”, otrzymamynew Person("Kumar",12)
telefon. Dlatego jest naturalne, że te dwie „osoby” nie są ze sobą powiązane.W ten sposób rozumiem Scalę (prawdopodobnie w bardziej „funkcjonalny” sposób). Nie jestem pewien, czy
tak naprawdę ma na myśli Scala. Przynajmniej nie lubię myśleć w ten sposób ...
źródło
Jak już mówi Kintaro, osoba jest metodą (z powodu def) i zawsze zwraca nową instancję Person. Jak się przekonałeś, zadziała, jeśli zmienisz metodę na var lub val:
Inną możliwością byłoby:
Jednak
person.age=20
w twoim kodzie jest to dozwolone, gdy odzyskaszPerson
instancję zperson
metody, aw tej instancji możesz zmienić wartośćvar
. Problem polega na tym, że po tej linii nie ma już odniesienia do tej instancji (ponieważ każde wywołanie funkcji toperson
utworzy nową instancję).To nic specjalnego, w Javie miałbyś dokładnie takie samo zachowanie:
źródło
Weźmy to:
i przepisz go za pomocą równoważnego kodu
Widzisz,
def
to metoda. Wykona się za każdym razem, gdy zostanie wywołana i za każdym razem zwróci (a)new Person("Kumar", 12)
. I to nie jest błąd w „przypisaniu”, ponieważ tak naprawdę nie jest to przypisanie, a jedynie wywołanieage_=
metody (dostarczonej przezvar
).źródło