【问题标题】:Scala's lazy arguments: How do they work?Scala 的懒惰论点:它们是如何工作的?
【发布时间】:2012-03-21 16:59:16
【问题描述】:

在解析器组合库的 Parsers.scala (Scala 2.9.1) 文件中,我似乎遇到了一个鲜为人知的 Scala 特性,称为“惰性参数”。这是一个例子:

def ~ [U](q: => Parser[U]): Parser[~[T, U]] = { lazy val p = q // lazy argument
  (for(a <- this; b <- p) yield new ~(a,b)).named("~")
}

显然,这里发生了一些事情,将名称调用参数 q 分配给惰性 val p

到目前为止,我还无法弄清楚它的作用以及它为何有用。有人可以帮忙吗?

【问题讨论】:

  • 你有没有努力去寻找自己?它是 Scala 语言的一部分,互联网搜索应该会在 scala lazy 上显示足够多的点击量。
  • @ziggystar:我已经进行了 2-3 次 Google 搜索,但找不到任何有用的信息。一些 Scala 功能请求中提到了惰性参数,但没有给出我能理解的解释。
  • @ziggystar:功能请求在这里:issues.scala-lang.org/browse/SI-240。此外,搜索scala lazy 甚至scala lazy argument 似乎不会产生很多有用的信息,因为您将主要获得关于更基本的东西的结果,例如惰性 val 和按名称调用。
  • 看起来你被那个评论弄糊涂了。它基本上只是一个名称调用参数和同一行上的lazy val。我以为你只是在问lazy val 是什么。

标签: scala lazy-evaluation


【解决方案1】:

按名称调用的参数在您每次请求时都会调用第一次调用惰性值,然后存储该值。如果您再次要求,您将获得存储的价值。

因此,像这样的模式

def foo(x: => Expensive) = {
  lazy val cache = x
  /* do lots of stuff with cache */
}

是最终的推迟工作,尽可能长且只做一次的模式。如果您的代码路径根本不需要x,那么它将永远不会被评估。如果您多次需要它,它只会被评估一次并存储以备将来使用。因此,您可以保证进行 0(如果可能)或 1(如果不是)次昂贵的调用。

【讨论】:

  • +1,我认为按名称调用在某些方面等于懒惰,但根本不是这样!感谢您的澄清...
【解决方案2】:

Scala 的维基百科文章甚至回答了 lazy 关键字的作用:

使用关键字lazy会延迟一个值的初始化,直到该值被使用。

此外,您在此代码示例中的q : =&gt; Parser[U] 是一个按名称调用的参数。以这种方式声明的参数保持未求值,直到您在方法中的某处显式求值。

以下是 scala REPL 中关于按名称调用参数如何工作的示例:

scala> def f(p: => Int, eval : Boolean) = if (eval) println(p)
f: (p: => Int, eval: Boolean)Unit

scala> f(3, true)
3

scala> f(3/0, false)

scala> f(3/0, true)
java.lang.ArithmeticException: / by zero
    at $anonfun$1.apply$mcI$sp(<console>:9)
    ...

如您所见,3/0 在第二次调用中根本没有得到评估。将惰性值与上述按名称调用的参数组合会产生以下含义:调用方法时不会立即评估参数q。相反,它被分配给惰性值p,它也不会立即评估。只有稍后,当使用p 时,这会导致对q 的评估。但是,由于pval,参数q 只会被评估一次,结果将存储在p 中以供以后在循环中重复使用。

您可以在 repl 中轻松看到,否则可能会发生多重评估:

scala> def g(p: => Int) = println(p + p)
g: (p: => Int)Unit

scala> def calc = { println("evaluating") ; 10 }
calc: Int

scala> g(calc)
evaluating
evaluating
20

【讨论】:

  • 最后一个例子有点混乱。它显示(在我的简化中),按名称调用意味着每次提到该名称时都会评估该值。所以,你提到“p”两次,它给出了两个评价。因此,为避免这种情况,您应该首先将评估保存在局部变量中:lazy val cache = p - "p" 只提到过一次,所以 Bobsyouruncle。
猜你喜欢
  • 1970-01-01
  • 2015-04-02
  • 2017-01-21
  • 2012-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多