W Scali możemy użyć co najmniej dwóch metod do modernizacji istniejących lub nowych typów. Załóżmy, że chcemy wyrazić, że coś można określić ilościowo za pomocąInt
. Możemy zdefiniować następującą cechę.
Niejawna konwersja
trait Quantifiable{ def quantify: Int }
A potem możemy użyć niejawnych konwersji do kwantyfikacji np. Ciągów znaków i list.
implicit def string2quant(s: String) = new Quantifiable{
def quantify = s.size
}
implicit def list2quantifiable[A](l: List[A]) = new Quantifiable{
val quantify = l.size
}
Po ich zaimportowaniu możemy wywołać metodę quantify
na łańcuchach i listach. Zauważ, że wymierna lista przechowuje swoją długość, więc pozwala uniknąć kosztownego przechodzenia przez listę przy kolejnych wywołaniachquantify
.
Klasy typu
Alternatywą jest zdefiniowanie „świadka”, Quantified[A]
który stwierdza, że pewien typ A
można określić ilościowo.
trait Quantified[A] { def quantify(a: A): Int }
Następnie udostępniamy instancje tego typu klasy dla String
i List
gdzieś.
implicit val stringQuantifiable = new Quantified[String] {
def quantify(s: String) = s.size
}
A jeśli następnie napiszemy metodę, która wymaga kwantyfikacji swoich argumentów, piszemy:
def sumQuantities[A](as: List[A])(implicit ev: Quantified[A]) =
as.map(ev.quantify).sum
Lub używając składni związanej z kontekstem:
def sumQuantities[A: Quantified](as: List[A]) =
as.map(implicitly[Quantified[A]].quantify).sum
Ale kiedy użyć której metody?
Teraz pojawia się pytanie. Jak mogę zdecydować między tymi dwoma koncepcjami?
Co zauważyłem do tej pory.
klasy typów
- klasy typów pozwalają na ładną składnię związaną z kontekstem
- z klasami typów nie tworzę nowego obiektu opakowującego przy każdym użyciu
- składnia związana z kontekstem nie działa już, jeśli klasa typu ma wiele parametrów typu; wyobraź sobie, że chcę określić ilościowo rzeczy nie tylko za pomocą liczb całkowitych, ale za pomocą wartości pewnego rodzaju ogólnego
T
. Chciałbym utworzyć klasę typuQuantified[A,T]
niejawna konwersja
- ponieważ tworzę nowy obiekt, mogę tam przechowywać wartości lub obliczyć lepszą reprezentację; ale czy powinienem tego unikać, ponieważ może się to zdarzyć kilka razy, a jawna konwersja prawdopodobnie zostanie wywołana tylko raz?
Czego oczekuję od odpowiedzi
Przedstaw jeden (lub więcej) przypadków użycia, w których różnica między oboma pojęciami ma znaczenie i wyjaśnij, dlaczego wolałbym jedno od drugiego. Również wyjaśnienie istoty tych dwóch pojęć i ich wzajemnych relacji byłoby miłe, nawet bez przykładu.