2009-09-08 11 views
16

W Scala mogę to zrobić:Scala nadrzędnymi non-abstrakcyjne def z var

trait SomeTrait { 
    protected def foo: String 
} 

class Wibble extends SomeTrait { 
    protected var foo = "Hello" 
} 

Ale nie mogę zrobić to samo, gdzie mogę przedstawić definicję domyślnego dla foo

trait SomeTrait { 
    protected def foo: String = "World" 
} 

class Wibble extends SomeTrait { 
    protected var foo = "Hello" //complains about lack of override modifier 

    override protected var foo = "Hello" //complains "method foo_ overrides nothing" 
} 

Dlaczego nie mogę tego zrobić?

EDIT: Po liście rozmowa na SCALA-users, mam raised this in trac

Odpowiedz

19

w Scala, kiedy piszesz var foo, kompilator Scala automatycznie generuje setter (tzw foo_=) i getter (o nazwie foo) i ustawia to pole jako prywatne (zobaczysz je jako prywatne, jeśli dekompilujesz klasę z "publicznymi" polami Scala z javap). Tak właśnie oznacza błąd "method foo_ = overrides nothing". W swojej funkcji nie zdefiniowałeś metody foo_=, a dla publicznego ustawiacza pól i pobierających zawsze są parami.

Jeśli nie podasz wartości domyślnej cechy (tj. Metody abstrakcyjnej), słowo kluczowe override nie jest konieczne. Dlatego w twoim pierwszym przykładzie getter przesłania metodę abstrakcyjną i ustawiającą ... po prostu tam jest. Kompilator nie narzeka. Ale kiedy podajesz rzeczywistą implementację metody w tej cechie, podczas nadpisywania musisz konkretnie napisać słowo kluczowe override. Podczas pisania protected var foo nie podano słowa kluczowego dla programu pobierającego i podczas pisania override protected var foo wskazano również kompilatorowi, że metoda foo_= ma zostać nadpisana, ale cecha nie ma takiej metody.

Ponadto, logicznie rzecz biorąc, nie można naprawdę przesłonić wartości def za pomocą var (biorąc pod uwagę ścisły widok nadpisywania, jak w poprzednim akapicie). A def jest logicznie funkcją (dajesz jej trochę wejścia, tworzy wyjście). A var jest podobna do funkcji no-arg, ale obsługuje także ustawianie jej wartości na coś innego, operację, która nie jest obsługiwana przez funkcję. Zamiast tego, gdybyś zmienił go na val, byłoby OK. To jest jak funkcja, która zawsze daje taki sam wynik (buforowany).

Jeśli chcesz mieć podobne zachowanie do var można zrobić coś takiego (poprzez wyraźny setter i pobierające):

class Wibble extends SomeTrait { 
    private var bar = "Hello" 
    override protected def foo = bar 
    protected def foo_=(v: String) { bar = v} 
} 

teraz można zrobić niczego można zrobić z :) var.

val x = new Wibble 
println(x.foo) // yields "Hello" 
x.foo = "Hello again" 
println(x.foo) // yields "Hello again" 
+0

Przepraszamy - popełniłem błąd - metoda pierwotnej cechy również powinna być chroniona. Nie jestem pewien, czy zgadzam się z tobą, że logicznie nie można zastąpić 'def' z' var'. Cała moja 'def' mówi, że oczekuję, że będzie jakiś accessor zwany' foo', który zwraca String - deklarowanie 'var' jest implementacją tego –

+0

Myślę, że się z tobą zgadzam. Zastanawiałem się, czy nie nadpisać, jako bardziej rygorystycznego pojęcia, gdy pisałem odpowiedź. Zmienię odpowiedź i zapewni poprawne rozwiązanie :). –

+0

Szkoda, że ​​nie ma "nadpisania def jako składni var" –