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 U
Int
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.
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. –
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