如果我定义一个简单的stringToInt函数并将其存储为val,那么一切都按预期工作,例如。
scala> def stringToInt1: (String => Int) = _.toInt
stringToInt1: String => Int
scala> stringToInt1("1")
res0: Int = 1
但是,如果我然后隐含,则会导致堆栈溢出:
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)
...
起初我怀疑这是因为下划线没有解决我的预期,但事实并非如此,因为这种隐式val的风格适用于以下简单函数:
scala> implicit def plusTwo: (Int => Int) = _ + 2
plusTwo: Int => Int
scala> plusTwo(2)
res2: Int = 4
如果我明确定义参数,则没有堆栈溢出:
scala> implicit def stringToInt3(s: String) = s.toInt
stringToInt3: (s: String)Int
scala> stringToInt3("1")
res3: Int = 1
(如果自己尝试这个并且最后一个案例堆栈溢出,请重新启动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
但为什么隐式转换会导致问题?
答案 0 :(得分:9)
添加其他回复。
toInt
上有没有 String
方法。 Scala必须找到一个隐式转换,它将产生一个具有toInt
方法的类型。
通常StringOps
转化提供此toInt
。
但是,Int
还有toInt
,因此scala会从String => Int
中找到您的转化,并确定它优先于StringOps
转化,因此适用它是递归的。
这就是StringToInt4
工作的原因,因为您明确地告诉编译器您想要什么转换。也许你可以把它写成:implicit def stringToInt5: (StringOps => Int) = _.toInt
或检查implicits是如何解决的,以及如何优先于另一个。
答案 1 :(得分:0)
请注意你在这里做的事情:
scala> def stringToInt1: (String => Int) = _.toInt
stringToInt1: String => Int
您正在定义方法(使用def
),该方法不带任何参数,并从String
返回函数到Int
。你是故意这样做的,还是因为你不完全理解语法?
您可以改为创建val
:
val stringToInt1: (String => Int) = _.toInt
现在,stringToInt1
是val
,其中包含将String
转换为Int
的功能。
使用stringToInt2
,Scala会以递归方式应用此方法。我不知道为什么在stringToInt2
而不是plusTwo
的情况下会这样做。
请注意,stringToInt3
与stringToInt1
和stringToInt2
不同。这是一个采用String
并返回Int
的方法,而不是不带参数的方法,并将函数从String
返回到Int
。