In Scala können wir mindestens zwei Methoden verwenden, um vorhandene oder neue Typen nachzurüsten. Angenommen, wir möchten ausdrücken, dass etwas mit einem quantifiziert werden kann Int
. Wir können das folgende Merkmal definieren.
Implizite Konvertierung
trait Quantifiable{ def quantify: Int }
Und dann können wir implizite Konvertierungen verwenden, um z. B. Zeichenfolgen und Listen zu quantifizieren.
implicit def string2quant(s: String) = new Quantifiable{
def quantify = s.size
}
implicit def list2quantifiable[A](l: List[A]) = new Quantifiable{
val quantify = l.size
}
Nachdem wir diese importiert haben, können wir die Methode quantify
für Zeichenfolgen und Listen aufrufen . Beachten Sie, dass die quantifizierbare Liste ihre Länge speichert, sodass das teure Durchlaufen der Liste bei nachfolgenden Aufrufen von vermieden wird quantify
.
Typklassen
Eine Alternative besteht darin, einen "Zeugen" zu definieren Quantified[A]
, der besagt, dass ein Typ A
quantifiziert werden kann.
trait Quantified[A] { def quantify(a: A): Int }
Wir stellen dann Instanzen dieser Typklasse für String
und List
irgendwo zur Verfügung.
implicit val stringQuantifiable = new Quantified[String] {
def quantify(s: String) = s.size
}
Und wenn wir dann eine Methode schreiben, die ihre Argumente quantifizieren muss, schreiben wir:
def sumQuantities[A](as: List[A])(implicit ev: Quantified[A]) =
as.map(ev.quantify).sum
Oder verwenden Sie die kontextgebundene Syntax:
def sumQuantities[A: Quantified](as: List[A]) =
as.map(implicitly[Quantified[A]].quantify).sum
Aber wann welche Methode anwenden?
Nun kommt die Frage. Wie kann ich mich zwischen diesen beiden Konzepten entscheiden?
Was mir bisher aufgefallen ist.
Typklassen
- Typklassen ermöglichen die nette kontextgebundene Syntax
- Mit Typklassen erstelle ich nicht bei jeder Verwendung ein neues Wrapper-Objekt
- Die kontextgebundene Syntax funktioniert nicht mehr, wenn die Typklasse mehrere Typparameter hat. Stellen Sie sich vor, ich möchte Dinge nicht nur mit ganzen Zahlen, sondern auch mit Werten eines allgemeinen Typs quantifizieren
T
. Ich möchte eine Typklasse erstellenQuantified[A,T]
implizite Konvertierung
- Da ich ein neues Objekt erstelle, kann ich dort Werte zwischenspeichern oder eine bessere Darstellung berechnen. Aber sollte ich das vermeiden, da es mehrmals vorkommen kann und eine explizite Konvertierung wahrscheinlich nur einmal aufgerufen wird?
Was ich von einer Antwort erwarte
Stellen Sie einen (oder mehrere) Anwendungsfälle vor, bei denen der Unterschied zwischen beiden Konzepten von Bedeutung ist, und erklären Sie, warum ich einen dem anderen vorziehen würde. Es wäre auch ohne Beispiel schön, die Essenz der beiden Konzepte und ihre Beziehung zueinander zu erklären.
size
einer Liste in einem Wert und sagen, dass es das teure Durchlaufen der Liste bei nachfolgenden zu quantifizierenden Aufrufen vermeidet, aber bei jedem Aufruf an quantify
die list2quantifiable
wird ausgelöst alles noch einmal, wodurch Quantifiable
das quantify
Eigentum wieder hergestellt und neu berechnet wird . Ich sage, dass es tatsächlich keine Möglichkeit gibt, die Ergebnisse mit impliziten Konvertierungen zwischenzuspeichern.