如何在Scala中链接含义?(How can I chain implicits in Scala?)

编程入门 行业动态 更新时间:2024-10-24 04:37:44
如何在Scala中链接含义?(How can I chain implicits in Scala?)

pimp-my-library模式允许我通过将该类的隐式转换提供给实现该方法的隐式转换,似乎将一个方法添加到类中。

然而,Scala不允许进行两次这样的隐式转换,所以我不能从A到C使用隐式的A到B和另一个隐含的B到C 有没有办法解决这个限制?

The pimp-my-library pattern allows me 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 I cannot got from A to C using an implicit A to B and another implicit B to C. Is there a way around this restriction?

最满意答案

Scala对自动转换有一个限制,以添加一种方法,即在尝试查找方法时不会应用多个转换。 例如:

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 restrictions object T1 { // to make it easy to test on REPL 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) // won't work println(5.total) println(new A(5).total) // works println(new B(5, 5).total) println(new C(5, 5, 10).total) }

编辑:自Scala 2.11 https://issues.scala-lang.org/browse/SI-7629 (您可以使用类型类型)后, 查看边界('<%')已被弃用

但是,如果隐式定义需要隐式参数本身(View bound),则Scala 根据需要寻找额外的隐式值。 从最后一个例子继续:

// 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) // works println(5.total) println(new A(5).total) println(new B(5, 5).total) println(new C(5, 5, 10).total) }

“魔法”,你可以说。 不是这样 这是编译器如何翻译每一个:

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 this println(bToC(aToB(toA(5))).total) println(bToC(aToB(new A(5))).total) // Just this println(bToC(new B(5, 5)).total) // No implicits required println(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 this println(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 required println(new C(5, 5, 10).total) }

因此,当bToC被用作隐式转换时, aToB和aToB作为隐式参数传递,而不是作为隐式转换链接。

编辑

相关利益问题:

关于类型,起因和优先级的讨论

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 restrictions object T1 { // to make it easy to test on REPL 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) // won't work println(5.total) println(new A(5).total) // works println(new B(5, 5).total) println(new C(5, 5, 10).total) }

EDIT: View bounds ('<%') are deprecated since Scala 2.11 https://issues.scala-lang.org/browse/SI-7629 (You can use type classes instead)

However, if an implicit definition requires an implicit parameter itself(View bound), Scala will look for additional implicit values for as long as needed. Continue 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) // works println(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 this println(bToC(aToB(toA(5))).total) println(bToC(aToB(new A(5))).total) // Just this println(bToC(new B(5, 5)).total) // No implicits required println(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 this println(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 required println(new C(5, 5, 10).total) }

So, while bToC is being used as an implicit conversion, aToB and toA are being passed as implicit parameters, instead of being chained as implicit conversions.

EDIT

Related question of interest:

A discussion on types, origin and precedence of implicits

更多推荐

本文发布于:2023-08-07 11:26:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1464223.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:含义   链接   如何在   implicits   Scala

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!