在不更改函数签名的情况下使参数延迟



给定:

scala> def f(x: Int, y: Int): Int = 
     |   if(x == 55) x else y
f: (x: Int, y: Int)Int
scala> def yFn: Int = {println("y"); 42}
yFn: Int

调用f(55, yFn)会导致f的评估,如y打印输出所示。

scala> f(55, yFn)
y
res0: Int = 55

f的签名如何保持不变:

(Int, Int) => Int

但是,是否必须在不将y作为by-name参数的情况下懒惰地计算y

f转换为宏将有效地执行您想要的操作:

import language.experimental.macros
import scala.reflect.macros.whitebox.Context
object Macros {
  def f(x: Int, y: Int): Int = macro fImpl
  def fImpl(c: Context)(x: c.Expr[Int], y: c.Expr[Int]): c.Expr[Int] = {
    import c.universe._
    c.Expr(q"if ($x == 55) $x else $y")
  }
}

f的签名有Int,而不是=> Int,但调用f(55, yFn)只会被if (55 == 55) 55 else yFn替换,不会评估yFn

从这里你可以看到,任何不查看其参数结构的宏都会有效地按名称获取它们;如果你想确保一个参数只被计算一次,你需要把它分配给一个局部变量:q"{ val x = $x; if (x == 55) x else $y }"

但是,如果要将f转换为对象而不是方法,这将丢失,因为生成的类的apply方法不会是宏(它不可能;宏不能实现抽象方法(当然,或覆盖具体方法((。

相关内容

最新更新