Domieszka (ang. mixin) to cecha (trait), która używana jest do komponowania klas.
abstract class A {
val message: String
}
class B extends A {
val message = "Jestem instancją klasy B"
}
trait C extends A {
def loudMessage = message.toUpperCase()
}
class D extends B with C
val d = new D
println(d.message) // wyświetli "Jestem instancją klasy B"
println(d.loudMessage) // wyświetli "JESTEM INSTANCJĄ KLASY B"
Klasa D
posiada nadklasę B
oraz domieszkę C
.
Klasy mogą mieć tylko jedną nadklasę, ale wiele domieszek (używając kolejno słów kluczowych extends
, a następnie with
).
Domieszki i nadklasy mogą posiadać tą samą nadklasę (typ bazowy).
Spójrzmy teraz na trochę ciekawszy przykład zawierający klasę abstrakcyjną.
abstract class AbsIterator {
type T
def hasNext: Boolean
def next(): T
}
Klasa ta zawiera abstrakcyjny typ type T
oraz standardowe metody iteracyjne hasNext
i next
.
class StringIterator(s: String) extends AbsIterator {
type T = Char
private var i = 0
def hasNext = i < s.length
def next() = {
val ch = s charAt i
i += 1
ch
}
}
Klasa StringIterator
przyjmuje parametr typu String
, może być ona użyta do iterowania po typach String (np. aby sprawdzić czy String zawiera daną literę).
Stwórzmy teraz cechę, która również rozszerza AbsIterator
.
trait RichIterator extends AbsIterator {
def foreach(f: T => Unit): Unit = while (hasNext) f(next())
}
Cecha RichIterator
implementuje metodę foreach
, która z kolei wywołuje przekazaną przez parametr funkcję f: T => Unit
na kolejnym elemencie (f(next())
) tak długo, jak dostępne są kolejne elementy (while (hasNext)
).
Ponieważ RichIterator
jest cechą, nie musi implementować abstrakcyjnych składników klasy AbsIterator
.
Spróbujmy teraz połączyć funkcjonalności StringIterator
oraz RichIterator
w jednej klasie.
object StringIteratorTest extends App {
class RichStringIter extends StringIterator("Scala") with RichIterator
val richStringIter = new RichStringIter
richStringIter foreach println
}
Nowo powstała RichStringIter
posiada StringIterator
jako nadklasę oraz RichIterator
jako domieszkę.
Mając do dyspozycji jedynie pojedyncze dziedziczenie, nie byli byśmy w stanie osiągnąć takiego stopnia elastyczności.
Contributors to this page:
Contents
- Wprowadzenie
- Podstawy
- Hierarchia typów
- Klasy
- Domyślne wartości parametrów
- Parametry nazwane
- Cechy
- Krotki
- Kompozycja klas przez domieszki
- Funkcje wyższego rzędu
- Funkcje zagnieżdżone
- Rozwijanie funkcji (Currying)
- Klasy przypadków
- Dopasowanie wzorców (Pattern matching)
- Obiekty singleton
- Wzorce wyrażeń regularnych
- Obiekty ekstraktorów
- For Comprehensions
- Klasy generyczne
- Wariancje
- Górne ograniczenia typów
- Dolne ograniczenia typów
- Klasy wewnętrzne
- Typy abstrakcyjne
- Typy złożone
- Jawnie typowane samoreferencje
- Parametry domniemane
- Konwersje niejawne
- Metody polimorficzne
- Lokalna inferencja typów
- Operatory
- Parametry przekazywane według nazwy
- Adnotacje
- Pakiety i importy
- Obiekty pakietu