Meines Wissens gibt es kein gemeinsames Merkmal in der Sammlungsbibliothek, das die Methode map
definiert (höchstwahrscheinlich, weil es unterschiedliche Signaturen für map
gibt).
Ich habe einen beobachtbaren Wert (denken Sie an eine Eigenschaft in einem UI-System), der ein Änderungsereignis hat. Die beobachtbaren Werte können mit einer map
-Methode gemappt werden.
Wenn wir jedoch mit einem Typ arbeiten, der bereits eine map
-Methode hat, sollten wir die eingebaute Methode von map
verwenden können.
Also statt:
prop map { x =>
x map { actualX =>
//etwas tun
}
}
Möchte ich es so verwenden:
prop map { actualX =>
//etwas tun
}
Ich habe einen vereinfachten Testfall. Zuerst die verschiedenen Teile, die ich benutze:
// den beobachtbaren Teil auslassen
trait ObservableValue[T] {
def value: T
}
trait LowerPriorityImplicits {
// Standardimplementierung, die eine reguläre map-Methode hinzufügt
implicit class RichObservableValue1[A](o: ObservableValue[A]) {
def map[B](f: A => B): ObservableValue[B] = new ObservableValue[B] {
def value = f(o.value)
}
}
}
object ObservableValue extends LowerPriorityImplicits {
// beschreibe einen Typ mit einer map-Methode
type HasMapMethod[A, Container[X]] = {
def map[B](f: A => B): Container[B]
}
// komplexe Implementierung, die die eingebaute map verwendet, wenn vorhanden
implicit class RichObservableValue2[A, Container[Z] <: HasMapMethod[Z, Container]](
o: ObservableValue[Container[A]]) {
def map[B](f: A => B): ObservableValue[Container[B]] =
new ObservableValue[Container[B]] {
def value = o.value.map(f)
}
}
}
Wenn in dem obigen Code etwas (oder vielleicht viel) falsch ist, lassen Sie es mich wissen. Ich möchte es so verwenden:
class TestCase extends ObservableValue[Option[Int]] {
def value = None
}
val x = new TestCase
x map { value =>
//dies schlägt fehl, weil der Compiler die Impliziten mit niedrigerer Priorität findet
(value: Int).toString
}
// die Methode selbst funktioniert gut
ObservableValue.RichObservableValue2(x) map { value =>
(value: Int).toString
}
Wenn ich Container[B]
in Any
ändere, wird die Implizite Konvertierung von RichObservableValue2
gefunden.
Mein Wissen darüber, wie Typen verwendet werden, um Implizite auszuwählen, ist begrenzt.
Ich habe versucht, die Antwort in den folgenden Quellen zu finden, aber das Thema ist etwas überwältigend:
- Wo sucht Scala nach Impliziten?
- Wie kann ich Implizite in Scala verketten?
- Scala: Präzedenz der impliziten Parameterauflösung
- http://eed3si9n.com/revisiting-implicits-without-import-tax
- Abschnitt 6.26.3 "Überlastungsaufklärung" im ScalaReference.pdf
Gibt es einen Weg, um diese Herausforderung zu lösen?
Bearbeiten
Ich kenne das FilterMonadic
-Trait für Sammlungen. Ich suche nach einer Lösung, die die map
-Methode erkennt, wie sie in der Klasse Option
definiert ist.
Zweites Update
Es scheint, dass die Variante von FilterMonadic
auch nicht funktioniert. Ich habe RichObservableValue3
zum Objekt RichObservableValue
hinzugefügt.
implicit class RichObservableValue3[A, C[Z] <: FilterMonadic[Z, C[Z]]](o: ObservableValue[C[A]]) {
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[C[A], B, That]): ObservableValue[That] = new ObservableValue[That] {
def value = o.value.map(f)
val change = o.change map (_ map f)
}
}
Und auch in diesem Fall wird diese Implizite Konvertierung nicht gewählt, obwohl ein List[Int]
ein gültiges Argument ist. Ich scheine eine Regel zu verpassen, die verwendet wird, wenn Implizite ausgewählt werden.