[转]Scala: How can I chain/nest implicit conversions?
原文:http://docs.scala-lang.org/tutorials/FAQ/chaining-implicits.html
The pimp my library pattern allows one to seemingly add a method to a class by making available an implicit conversion from that class to one that implements the method.
Scala does not allow two such implicit conversions taking place, however, so one cannot got from Ato C using an implicit A to B and another implicit B to C. Is there a way around this restriction?
Scala has a restriction on automatic conversions to add a method, which is that it won’t apply more than one conversion in trying to find methods. For example:
class A(val n: Int)class B(val m: Int, val n: Int)class C(val m: Int, val n: Int, val o: Int) {def total = m + n + o}// This demonstrates implicit conversion chaining restrictionsobject T1 { // to make it easy to test on REPLimplicit def toA(n: Int): A = new A(n)implicit def aToB(a: A): B = new B(a.n, a.n)implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)// won't workprintln(5.total)println(new A(5).total)// worksprintln(new B(5, 5).total)println(new C(5, 5, 10).total)}
However, if an implicit definition requires an implicit parameter itself, Scala will look for additional implicit values for as long as needed. Continuing from the last example:
// def m[A <% B](m: A) is the same thing as// def m[A](m: A)(implicit ev: A => B)object T2 {implicit def toA(n: Int): A = new A(n)implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)// worksprintln(5.total)println(new A(5).total)println(new B(5, 5).total)println(new C(5, 5, 10).total)}
“Magic!”, you might say. Not so. Here is how the compiler would translate each one:
object T1Translated {implicit def toA(n: Int): A = new A(n)implicit def aToB(a: A): B = new B(a.n, a.n)implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)// Scala won't do thisprintln(bToC(aToB(toA(5))).total)println(bToC(aToB(new A(5))).total)// Just thisprintln(bToC(new B(5, 5)).total)// No implicits requiredprintln(new C(5, 5, 10).total)}object T2Translated {implicit def toA(n: Int): A = new A(n)implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)// Scala does thisprintln(bToC(5)(x => aToB(x)(y => toA(y))).total)println(bToC(new A(5))(x => aToB(x)(identity)).total)println(bToC(new B(5, 5))(identity).total)// no implicits requiredprintln(new C(5, 5, 10).total)}
So, while bToC is being used as an implicit conversion, aToB and toA are being passed asimplicit parameters, instead of being chained as implicit conversions.
See also:
This question and answer were originally submitted on Stack Overflow.

浙公网安备 33010602011771号