2010-07-23 7 views
11

Ich habe this class in Scala:Warum schlägt die Fehlfunktion von Scala hier fehl?

object Util { 
    class Tapper[A](tapMe: A) { 
    def tap(f: A => Unit): A = { 
     f(tapMe) 
     tapMe 
    } 

    def tap(fs: (A => Unit)*): A = { 
     fs.foreach(_(tapMe)) 
     tapMe 
    } 
    } 

    implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap) 
} 

Jetzt

"aaa".tap(_.trim) 

nicht kompiliert,

error: missing parameter type for expanded function ((x$1) => x$1.trim)

Warum die Art, wie String geschlossen wird, um den Fehler nicht zu geben? Aus dem Fehler scheint es, dass die implizite Konvertierung ausgelöst wird (andernfalls wäre der Fehler in den Zeilen "tap ist kein Mitglied der Klasse String"). Und es scheint, dass die Konvertierung zu Tapper[String] sein muss, was bedeutet, dass der Typ des Arguments String => Unit (oder (String => Unit)*) ist.

Die interessante Sache ist, dass, wenn ich entweder von tap Definitionen auskommentieren, dann kompiliert es.

Antwort

17

6.26.3 Overloading Resolution

One first determines the set of functions that is potentially applicable based on the shape of the arguments

...

If there is precisely one alternative in B, that alternative is chosen.

Otherwise, let S1, . . . , Sm be the vector of types obtained by typing each argument with an undefined expected type.

Beide Überlastungen von tap sind potenziell anwendbar (bezogen auf die ‚Form‘ der Argumente, die für die arity und Typkonstruktoren Funktionenn Konten).

So sind die typer läuft wie wäre es mit:

val x = _.trim 

und schlägt fehl.

Ein intelligenterer Algorithmus könnte die Mindestobergrenze des entsprechenden Parametertyps jeder Alternative verwenden und diesen als erwarteten Typ verwenden. Aber diese Komplexität ist es nicht wirklich wert, IMO. Überladen hat viele Eckfälle, das ist aber ein anderes.

Aber es gibt einen Trick, den Sie in diesem Fall benutzen können, wenn Sie wirklich eine Überlastung benötigen, die einen einzelnen Parameter akzeptiert:

object Util { 
    class Tapper[A](tapMe: A) { 
    def tap(f: A => Unit): A = { 
     f(tapMe) 
     tapMe 
    } 

    def tap(f0: A => Unit, f1: A => Unit, fs: (A => Unit)*): A = { 
     (Seq(f0, f1) ++ fs).foreach(_(tapMe)) 
     tapMe 
    } 
    } 

    implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap) 

    "".tap(_.toString) 
    "".tap(_.toString, _.toString) 
    "".tap(_.toString, _.toString, _.toString) 
} 
+0

Ausgezeichnete Idee, danke! Ich dachte, ich müsste sie anders benennen. –

+3

Du wirst schnell der neue Daniel, Jason! –

+2

@oxbow Noch besser, er zitiert oft die Spezifikation, was eine gute Sache ist. –

Verwandte Themen