考虑以下代码:
class DelayedInt(val value: Int) {
var locked = true
}
object DelayedInt {
implicit def delayedIntToInt(del: DelayedInt) = {
if (del.locked) throw new RuntimeException("not yet!")
del.value
}
}
object Main {
var queue: Seq[() => Int] = Seq.empty
def queueInt(int: => Int): Unit = {
queue :+= int _
}
def printQueue(): Unit =
for (f <- queue)
println("int is: " + f.apply())
def main(args: Array[String]): Unit = {
val di = new DelayedInt(42)
// println(5 + di) // throws exception
queueInt(5 + di) // OK
queueInt(di) // OK
di.locked = false
printQueue()
}
}
除非显式解锁,否则DelayedInt
类在转换为int时会引发异常。
println
函数必须失败,因为它调用隐式转换。
queueInt
函数工作正常,似乎是因为它使用了基于名字的参数,并且隐式转换直到printQueue
才被调用。
我不清楚Scala如何决定何时运行隐式转换?特别是在queueInt(di)
的情况下,必须以某种方式弄清楚结果将是正确的类型,而无需使用隐式转换。
要对此进行评估的步骤是什么?
答案 0 :(得分:2)
我的理解是,在queueInt(5 + di)
和queueInt(di)
两种情况下,都应在进行任何评估之前进行隐式转换。 queueInt
接受一个基于名字的参数,然后由于int _
的语法,它向queue: Seq[() => Int]
添加了一个未应用的 function ,因此传入的参数不会在之后被求值queueInt
完成。仅当调用printQueue()
时,queue
的元素函数才因f.apply()
调用而求值。
在println(5 + di)
的情况下,该参数未按名称传递,因此在隐式转换后,它会在之前求值,然后将其传递给println
,因此抛出该异常,但是像queueInt
情况一样,隐式转换仍然会首先发生。
这里似乎没有什么奇怪的事情。
答案 1 :(得分:2)
我不清楚Scala如何决定何时运行隐式转换?
不是,直接。它只是将其插入所需类型所需的位置,因此在编译器阶段之后,您的代码将变为
val di = new DelayedInt(42)
// println(5 + DelayedInt.delayedIntToInt(di)) // throws exception
queueInt(5 + DelayedInt.delayedIntToInt(di)) // OK
queueInt(DelayedInt.delayedIntToInt(di)) // OK
di.locked = false
printQueue()
,然后queueInt
情况对于按名称参数正常运行。
它必须以某种方式弄清楚结果将是正确的类型,而不使用隐式转换。
这当然是基于类型的,不需要运行任何东西。