2013-02-18 4 views
8

ich konvertieren haben den Anwendungsfall folgende, die oft in meinem Code auftritt:Wie eine Liste [A] in einer Liste [B] mit einer impliziten Umwandlung

  • A Collection [A]
  • eine implizite Umwandlung von A bis B

und ich möchte eine Sammlung von B erhalten ich implizit wie die folgende verwenden:

case class Items(underlying:List[B]) 
    import B._ 
    def apply(a:List[A]):Items = { 
    val listOfB= a.map {implicitly[A=>B]} 
    Items(listOfB) 
    } 

Was ist der eleganteste Weg, das in Scala zu tun, vielleicht mit der Hilfe von Scalaz, dasselbe zu tun?

Edit: das Ziel meiner Frage ist es, einen idiomatischen Weg, um einen gemeinsamen Ansatz unter Bibliotheken/Entwickler zu finden. In einem solchen Sinn ist die Entwicklung meiner eigenen pimp-my-Bibliothek-Lösung etwas, was ich nicht mag, weil andere Leute, die meinen Code schreiben, die Existenz dieser Konvertierung nicht kennen und sie nicht verwenden würden, und sie werden ihre eigenen umschreiben. Ich bevorzuge einen Bibliotheksansatz für diese allgemeinen Funktionen und deshalb frage ich mich, ob in Scalaz eine solche Funktion existiert.

Antwort

14

Es ist ziemlich einfach, wenn Sie die Typen kennen. Zunächst implizite Konvertierung A-B:

implicit def conversion(a: A): B = //... 

dann müssen Sie implizite Konvertierung List[S]-List[T] wo S und T sind beliebige Typen, für die implizite Konvertierung S-T existiert:

implicit def convList[S, T](input: List[S])(implicit c: S => T): List[T] = 
    input map c 

Dies sollte dann Arbeit:

val listOfA: List[A] = //... 
val listOfB: List[B] = listOfA 

, die durch den Compiler behoben:

val listOfB: List[B] = convList(listOfA)(conversion) 

wo SA und T ist B.

+0

Gehört es irgendwie zu einigen Standardbibliotheken? Ich hasse es, das Rad neu zu erfinden – Edmondo1984

+0

@ Edmondo1984: Ich weiß es nicht, ich habe es gerade erst geschrieben, aber ich erfinde Rad vielleicht auch neu. BTW las meine Antwort noch einmal, ich generierte die Lösung, so dass Sie nur eine implizite ConvList-Konvertierung für alle konvertierbaren Typen benötigen. –

9

Ich würde hier nicht eine implizite Konvertierung verwenden, sondern eine in der Klasse gebunden Ansicht:

case class Foo(x: Int) 
case class Bar(y: Int) 
implicit def foo2Bar(foo: Foo) = Bar(foo.x) 
case class Items[A <% Bar](xs: List[A]) { 
    def apply(x: Int): Bar = xs(x) 
} 

Sie jetzt eine Instanz von Items mit einer Liste von Foo erstellen und sie intern verwenden, als ob sie waren Bar s.

scala> Items(List(Foo(1))) 
res8: Items[Foo] = Items(List(Foo(1))) 

scala> res8(0) 
res9: Bar = Bar(1) 

bearbeiten:

Einige Klärung, warum würde ich nicht eine implizite Konvertierung verwenden:

Implizite Konvertierungen können gefährlich sein, wenn sie in ihrem Umfang und aus Versehen konvertieren, dass sie sollte nicht konvertieren. Ich würde das Zeug immer explizit oder über Ansichtsgrenzen konvertieren, weil ich es dann steuern kann. Auch die implizite Konvertierung kann die Größe Ihres Codes verringern, macht es aber für andere auch schwieriger verständlich. Ich würde nur die implizite Konvertierung für das Muster "Meine Bibliothek erweitern" verwenden.

edit2:

Sie könnten jedoch eine Methode zur Sammlung Typen hinzufügen, die diese Umwandlung der Fall ist, wenn ein solches Verfahren in Anwendungsbereich ist:

trait Convertable[M[A], A] { 
    def convertTo[B](implicit f: A => B): M[B] 
} 

implicit def list2Convertable[A](xs: List[A]) = new Convertable[List, A] { 
    def convertTo[B](implicit f: A => B) = xs.map(f) 
} 

scala> implicit def int2String(x: Int) = x.toString 
int2String: (x: Int)String 

scala> List(1,2,3).convertTo[String] 
res0: List[String] = List(1, 2, 3) 

Statt eine weitere implizite Konvertierung hier der Verwendung Würde ich wahrscheinlich stattdessen eine typeclass verwenden, aber ich denke, dass Sie die Grundidee bekommen.

1

Arbeiten, beginnend mit Scala 2.10:

implicit class ListOf[A](val list: List[A]) { 
    def of[B](implicit f: A => B): List[B] = list map f 
} 
implicit def int2String(i: Int) = i.toString 

// Usage 
List(1,2,3).of[String] 
+0

Das funktioniert nur in scala 2.10 – mericano1

+0

Ja, es ist bereits out – idonnie

+0

Ich weiß, ich habe nur darauf hingewiesen, es wäre vorteilhaft, dass in der Antwort – mericano1

-1

In meinem Code, ich verwende eine allgemeinere Version von Tomasz‘Lösung angepasst, über der kümmert sich um alle Traversable Instanzen

/** Implicit conversion for Traversable instances where the elements are convertable */ 
implicit def convTrav[S, T, I[S] <: Traversable[S]](input: I[S])(implicit c: S => T): I[T] = 
    (input map c).asInstanceOf[I[T]] 

(Dies ist für mich arbeiten, obwohl ich gerne wissen würde, ob erfahrene Scala-Programmierer denken, dass dies aus irgendeinem Grund eine schlechte Idee ist, abgesehen von den üblichen Vorbehalte gegenüber impliziten Konvertierungen)

Verwandte Themen