2016-10-09 1 views
3

Ich habe die Funktion ev nirgendwo definiert. Wie funktioniert der folgende Code? Muss nicht implicits irgendwo im Bereich für ihre Verwendung definiert werden?Übergabe und Verwendung einer impliziten Funktion, ohne sie zu definieren

def same[T, U](x: U)(implicit ev: U => T): T = {ev(x)} 
same(2) // 2 
+2

Um @TravisBrown Antwort zu erweitern, können Sie auch tun: 'same [Long, Int] (2)' und sehen, dass es noch kompiliert, weil 'Int' eine implizite namens' int2long' definiert ist, die machen würde diese Arbeit. Wenn Magie so passiert, denke immer darüber nach, welche Implikate für dich in den Geltungsbereich gebracht werden, ohne sie ausdrücklich anzufordern. –

+0

Dank Yuval war der verwirrende Teil, auf welcher Grundlage der Compiler das 'T' ableitete (bevor nach implizit gesucht wurde). Dies ist mein erster Pinsel mit der impliziten Methode $ conforms. – Samar

Antwort

5

Jedes Mal, wenn Sie Fragen wie diese haben, ein guter Anfang ist durch die Scala Reflection-API in der REPL mit dem Compiler zu fragen, was los ist:

scala> import scala.reflect.runtime.universe.{ reify, showCode } 
import scala.reflect.runtime.universe.{reify, showCode} 

scala> def same[T, U](x: U)(implicit ev: U => T): T = ev(x) 
same: [T, U](x: U)(implicit ev: U => T)T 

scala> showCode(reify(same(2)).tree) 
res0: String = $read.same(2)(Predef.$conforms) 

So ev wird zur Verfügung gestellt von Predef.$conforms, eine implizite Methode, die Ihnen eine Instanz von A <:< A für jede A gibt, wobei <:<Function1 erweitert.

Also das ist ein Hinweis. Um den Rest herauszufinden, muss man ein wenig über Typinferenz nachdenken. Wenn Sie same(2) aufrufen, stellt der Compiler fest, dass der Ausdruck 2 den Typ Int hat, und folgert, dass UInt ist. Als nächstes muss es herausfinden, was T ist, und dafür muss es nach impliziten Funktionen von Int bis x für einen Typ x suchen.

Hier $conforms kommt in. Es ist das einzige Verfahren, das in Umfang, so dass die Compiler es wählt, was bedeutet, dass ev vom Typ Int => Int und T hat Int zu sein, und du bist fertig.

+0

Das ist ein schöner Trick. Ich benutze immer 'scalac -Xprint..', um den Baum zu betrachten. –

+0

@YuvalItzchakov Ja, 'scalac -Xprint' ist auch nützlich, aber ich finde es lauter und weniger praktisch für in sich geschlossene Beispiele wie dieses. –

+0

Es bringt definitiv viel mehr Lärm. Ich werde mich daran erinnern :) –

Verwandte Themen