2017-01-22 1 views
5

Ich stolperte über Predef.StringCanBuildFrom überraschende Implementierung, die Annahmen bricht, die ich auf CanBuildFrom in meinem Code machte. Hier ist die Umsetzung:Predef.StringCanBuildFrom Verhalten

implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] = 
    new CanBuildFrom[String, Char, String] { 
     def apply(from: String) = apply() 
     def apply() = mutable.StringBuilder.newBuilder 
} 

Es scheint völlig unnatürlich, dass apply(String) einfach den Parameter ignoriert. Für mich sollte die korrekte Umsetzung

implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] = 
    new CanBuildFrom[String, Char, String] { 
     def apply(from: String) = apply() ++= from 
     def apply() = mutable.StringBuilder.newBuilder 
} 

sein, aber es scheint so trivial, dass ich nicht glaube, kann ich die ony eines bin haben entdeckt, dass, da die Sprache existiert. Ich war versucht, ein Problem dafür zu lösen, aber wenn ich einen guten Grund verpasse, nicht zu tun, was ich vorgeschlagen habe, bitte sag es mir!

Antwort

3

Ich denke, Sie missverstehen den Zweck von apply(from).

Es Dokumentation sagt:

auf Anfrage einer Sammlung einen neuen Builder erstellt.
@param von die Sammlung, die den Ersteller anfordert, erstellt werden.
@return ein Builder für Sammlungen des Typs To mit Elementtyp Elem. Das Collections-Framework ordnet normalerweise Dinge an, sodass der erstellte Builder die gleiche Art der Sammlung wie from erstellt.

So wird es verwendet, um den Generator mit dem Laufzeittyp der Sammlung aufzulösen und vielleicht einige Hilfsdaten aus der ursprünglichen Sammlung zu kopieren. Zum Beispiel ist die Implementierung in scala.collection.generic.GenTraversableFactory#GenericCanBuildFrom einfach def apply(from: Coll) = from.genericBuilder[A]. Wie Sie sehen, werden keine tatsächlichen Daten aus der Argumentsammlung kopiert.

Eigentlich Ihre Implementierung von CanBuildFrom wäre falsch Ergebnisse für die Standardimplementierungen von map, flatMap und anderen generischen Funktionen erzeugen:

import scala.collection.generic.CanBuildFrom 
import scala.collection.mutable 

implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] = 
    new CanBuildFrom[String, Char, String] { 
    def apply(from: String) = apply() ++= from 
    def apply() = mutable.StringBuilder.newBuilder 
    } 

scala> "foo".map(identity)(stringCanBuildFrom) 
res1: String = foofoo 
+0

Mmm, soll ich weitere Beispiele für Verwendungen gelesen habe. Das stimmt, sie gehen immer davon aus, dass ein Builder leer initialisiert ist, was das Duplikat "foo" in Ihrem Beispiel erklärt. Prost :) – Dici