为什么这个简单的隐式stringToInt函数会导致堆栈溢出?

Rhe*_*ese 5 scala implicit scala-2.10

如果我定义一个简单的stringToInt函数并将其存储为val,那么一切都按预期工作,例如

scala> def stringToInt1: (String => Int) = _.toInt
stringToInt1: String => Int

scala> stringToInt1("1")
res0: Int = 1
Run Code Online (Sandbox Code Playgroud)

但是,如果我然后隐藏它,它会导致堆栈溢出:

scala> implicit def stringToInt2: (String => Int) = _.toInt
stringToInt2: String => Int

scala> stringToInt2("1")
java.lang.StackOverflowError
at .stringToInt2(<console>:7)
at $anonfun$stringToInt2$1.apply(<console>:7)
at $anonfun$stringToInt2$1.apply(<console>:7)
...
Run Code Online (Sandbox Code Playgroud)

起初我怀疑这是因为下划线没有解决我的预期,但情况并非如此,因为这种隐式val的样式适用于以下简单函数:

scala> implicit def plusTwo: (Int => Int) = _ + 2
plusTwo: Int => Int

scala> plusTwo(2)
res2: Int = 4
Run Code Online (Sandbox Code Playgroud)

如果我显式定义参数,没有堆栈溢出:

scala> implicit def stringToInt3(s: String) = s.toInt
stringToInt3: (s: String)Int

scala> stringToInt3("1")
res3: Int = 1
Run Code Online (Sandbox Code Playgroud)

(如果自己尝试这个并且最后一个案例堆栈溢出,请重新启动scala控制台并重做最后一步)

所以我的问题是,为什么原来的隐含没有正确解决?

编辑

好在这里深入挖掘,似乎问题是从String到StringOps的隐式转换.如果我们削减它,它工作正常:

scala> import scala.collection.immutable.StringOps
import scala.collection.immutable.StringOps

scala> implicit def stringToInt4: (String => Int) = new StringOps(_).toInt
stringToInt4: String => Int

scala> stringToInt4("1")
res4: Int = 1
Run Code Online (Sandbox Code Playgroud)

但为什么隐式转换会导致问题呢?

Mor*_*mer 9

添加到其他回复.

没有 toInt对方法String.Scala必须找到一个隐式转换,它将产生一个具有toInt方法的类型.

通常StringOps转换提供此功能toInt.但是Int toInt,所以scala会从转换中找到String => Int并确定它优先于StringOps转换,因此会递归应用它.

这就是为什么StringToInt4有效,因为你明确告诉编译器你想要什么转换.也许你可以把它写成:implicit def stringToInt5: (StringOps => Int) = _.toInt或者检查implicits是如何解决的,以及如何优先于另一个.