Kiedyś tak myślałem private val
i tak private final val
jest, dopóki nie zobaczyłem sekcji 4.1 w Scala Reference:
Definicja wartości stałej ma postać
final val x = e
gdzie e jest wyrażeniem stałym (§ 6.24). Ostateczny modyfikator musi być obecny i nie można podawać adnotacji typu. Odniesienia do stałej wartości x same są traktowane jako wyrażenia stałe; w generowanym kodzie są zastępowane prawą stroną definicji e.
Napisałem test:
class PrivateVal {
private val privateVal = 0
def testPrivateVal = privateVal
private final val privateFinalVal = 1
def testPrivateFinalVal = privateFinalVal
}
javap -c
wynik:
Compiled from "PrivateVal.scala"
public class PrivateVal {
public int testPrivateVal();
Code:
0: aload_0
1: invokespecial #19 // Method privateVal:()I
4: ireturn
public int testPrivateFinalVal();
Code:
0: iconst_1
1: ireturn
public PrivateVal();
Code:
0: aload_0
1: invokespecial #24 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_0
6: putfield #14 // Field privateVal:I
9: return
}
Kod bajtowy jest taki, jak powiedział Scala Reference: private val
nie private final val
.
Dlaczego scalac nie traktuje po prostu private val
jako private final val
? Czy jest jakiś podstawowy powód?
val
jest już niezmienne, dlaczego w ogóle potrzebujemyfinal
słowa kluczowego w Scali? Dlaczego kompilator nie może traktować wszystkichval
tak samo jakfinal val
s?private
modyfikator zakresu ma taką samą semantykę jakpackage private
w Javie. Możesz chcieć powiedziećprivate[this]
.private
chodzi mi o to, że jest to widoczne tylko dla instancji tej klasy,private[this]
tylko ta instancja - z wyjątkiem instancji tej samej klasy ,private
nie pozwala nikomu (w tym z tego samego pakietu) na dostęp do wartości.Odpowiedzi:
Tak więc to tylko przypuszczenie, ale w Javie była to wieczna irytacja, że końcowe zmienne statyczne z literałem po prawej stronie są wstawiane do kodu bajtowego jako stałe. Z pewnością daje to korzyści w zakresie wydajności, ale powoduje zerwanie binarnej zgodności definicji, jeśli „stała” kiedykolwiek ulegnie zmianie. Definiując ostateczną zmienną statyczną, której wartość może wymagać zmiany, programiści Java muszą uciekać się do hacków, takich jak inicjowanie wartości za pomocą metody lub konstruktora.
Wartość w Scali jest już ostateczna w sensie Java. Wygląda na to, że projektanci Scali używają redundantnego modyfikatora final do oznaczenia „pozwolenia na wstawianie stałej wartości”. Tak więc programiści Scali mają pełną kontrolę nad tym zachowaniem bez uciekania się do hacków: jeśli chcą wbudowanej stałej, wartości, która nigdy nie powinna się zmieniać, ale jest szybka, piszą „wartość końcowa”. jeśli chcą elastyczności w zmianie wartości bez naruszania zgodności binarnej, po prostu „val”.
źródło
private val
naprivate final val
?val
w drugim akapicie?Myślę, że zamieszanie tutaj wynika z pomieszania niezmienności z semantyką finału.
val
s mogą być przesłonięte w klasach potomnych i dlatego nie mogą być traktowane jako ostateczne, chyba że są wyraźnie oznaczone jako takie.@Brian REPL zapewnia zakres klas na poziomie liniowym. Widzieć:
źródło
private val
. Czy można to zastąpić?