目标类型的隐式转换和名称参数

时间:2019-06-29 11:00:16

标签: scala

考虑以下代码:

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)的情况下,必须以某种方式弄清楚结果将是正确的类型,而无需使用隐式转换。

要对此进行评估的步骤是什么?

2 个答案:

答案 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情况对于按名称参数正常运行。

  

它必须以某种方式弄清楚结果将是正确的类型,而不使用隐式转换。

这当然是基于类型的,不需要运行任何东西。