隐式尺度是隐式的

Scala implicit implicit

我想在我的代码中做一些隐含的魔法,但问题很简单,我已经把它提取出来了。这似乎有点奇怪,因为根据我的阅读,以下内容应该有效。

   implicit class Foo(value: Double) {
      def twice = 2*value
    }

    2.0.twice

    implicit def strToDouble(x: String) = Try(x.toDouble) match {
      case Success(d) => d
      case Failure(_) => 0.0
    }

    strToDouble("2.0").twice
    val a: Double = "2.0"
    val b: Double = "equals 0.0"
    "2.0".twice 
    

我遇到编译错误

 value twice is not a member of String
[error]     "2.0".twice

我得到你的编译器,两次是为 Doubles 定义的,而不是 Strings。但我确实告诉过你如何从 Strings 到 Doubles,这里没有歧义(据我所知),所以你不应该注意到 "2.0".twice 可以通过 strToDouble("2.0").twice?

来完成

我是不是漏掉了什么?或者这是一种优化,以便编译器不会尝试 implicits 的所有可能排列(这将以超指数方式增长,我认为是阶乘)。我想我真的在寻找对此的确认或拒绝。

谢谢

如果你希望扩展方法在隐式转换后仍然适用,你可以修正隐式的定义class

implicit class Foo[A](value: A)(implicit ev: A => Double) {
  def twice: Double = 2 * value
}

implicit def strToDouble(x: String): Double = ???

2.0.twice   //compiles
"2.0".twice //compiles

I get you compiler, twice is defined for Doubles, not Strings. But I did tell you how to go from Strings to Doubles, and there is no ambiguity here (as far as I can tell), so shouldn't you be able to note that "2.0".twice can be done by doing strToDouble("2.0").twice?

根据规范,隐式转换仅适用于三种情况

https://scala-lang.org/files/archive/spec/2.13/07-implicits.html#views

2.0.twiceFoo(2.0).twice的转换是第二种情况,"2.0"strToDouble("2.0")的转换是第一种情况。如您所见,没有项目可以将它们一起应用。因此,如果您希望它们一起适用,您应该像我上面显示的那样明确指定。

同样,如果您定义了从 AB 和从 BC 的转换,这并不意味着您有从 A 的转换至 C

case class A(i: Int)
case class B(i: Int)
case class C(i: Int)
implicit def aToB(a: A): B = B(a.i)
implicit def bToC(b: B): C = C(b.i)

A(1): B    // compiles
B(1): C    // compiles
// A(1): C //doesn't compile