2013-04-02 13 views
7

Jeśli piszę:Jak zainicjować wartość z cechy podtypu?

trait T { 
    val t = 3 
    val u = 1::t::Nil 
} 

class U extends T { 
    override val t = 2 
} 

(new U).u 

pokazuje to.

List(1, 0) 

Jak należy zmienić powyższy kod, aby wyświetlić następujące:

List(1, 2) 

tj override val t ustawia wartość t dla u w cechy T?

+1

można zdefiniować u jako 'lazy val' –

Odpowiedz

12

Jednym ze sposobów, aby to zrobić, aby opóźnić ocenę u za pomocą def lub lazy val następująco:

trait T { 
    def t = 3 
    def u = 1::t::Nil 
} 

class U extends T { 
    override def t = 2 
} 

(new U).u 

lub

trait T { 
    val t = 3 
    lazy val u = 1::t::Nil 
} 

class U extends T { 
    override val t = 2 
} 

(new U).u 

Różnice są następujące:

  • val powoduje wyliczenie wyrażenia podczas inicjowania
  • def sprawia wyrazem oceniać każdorazowo u służy
  • lazy val sprawia, że ​​ocenia się na pierwszym u użytkowania i buforuje wynik
10

Spróbuj użyć wczesnego inicjator:

scala> trait T { 
    | val t = 3 
    | val u = 1::t::Nil 
    | } 
defined trait T 

scala> class U extends { 
    | override val t = 2; 
    | } with T 
defined class U 

scala> (new U).u 
res1: List[Int] = List(1, 2) 

Zobacz przykład here, aby uzyskać więcej informacji na temat wczesnej inicjalizacji.

+0

Chociaż poprawne, ze względu na czytelność, wolę używać metody pamięci podręcznej z leniwymi vals. Jeśli muszę dodać kod do mojej klasy U, nie mogę umieścić go w nawiasach, potrzebuję utworzyć inną grupę, tak jak klasa U rozszerza {przesłaniam wartość val t = 2} za pomocą T {... mój kod tutaj ... } –

+0

Problem z tym podejściem polega na tym, że każdy dostęp jest zsynchronizowany, aby upewnić się, że 'lazy val' jest w rzeczywistości gotowy. Spowalnia aplikację i nie należy jej używać w sposób ślepy na krytycznych ścieżkach. –

4

Wszystkie style oznajmujące scala są tylko złudzeniem. Scala jest zbudowana na jvm i działa jak Java.

Evetything jest klasą i powinno być niezależne od jego użycia (java nie jest w języku C++ i obsługuje przyrostową kompilację z jej zaletami i wadami). Każda cecha ma swój własny kod inicjujący, a klasa wielu cech uruchamia odpowiedni kod inicjalizacyjny jeden po drugim. Jeśli użyjesz jakiejkolwiek wartości AnyRef, która jest zadeklarowana tylko w podklasie, wówczas jej wartość zostanie ustawiona na wartość null podczas inicjowania.

Przestrzegam zasady określania konwencji: każdy znak powinien być albo ostateczny, albo leniwy (why using plain val in non-final classes). Nie obchodzi mnie więc kolejność inicjalizacji i może udawać, że używam języka deklaratywnego.

Używam również opcji -Xcheckinit: Dodaj sprawdzanie czasu wykonywania do akcesorów pól.

Powiązane problemy