【问题标题】:Call by value with values interpreted as zero-argument functions vs call by name按值调用,将值解释为零参数函数与按名称调用
【发布时间】:2016-12-30 20:41:30
【问题描述】:

comment 中,@Ben 建议按名称调用等同于按值调用,其中值是零参数函数。如果我理解正确的话,

def callByName(x: => Int) = {
  // some code
}
callByName(something())

等价于

def callByValue(x: () => Int) = {
  // same code as above, but all occurrences of x replaced with x()
}
callByValue(()=>something())

(编辑:我修正了@MichaelZajac,@LukaJacobowitz 指出的签名错误:最初,它说callByValue(x: Int)。)

换句话说,整个“按名称调用”概念只是语法糖:它所做的一切都可以使用“按值调用”来实现(只需几个额外的击键)。如果为真,则很容易理解按名称调用;事实上,我在 python 中使用过这种技术(python 具有一流的功能)。

但是,在comments 的更下方,讨论变得更加混乱,我觉得事情并不那么简单。

那么“点名”还有什么更实质的东西吗?还是只是编译器自动创建零参数函数?

【问题讨论】:

    标签: scala


    【解决方案1】:

    我假设您的意思是您的 callByValue 函数采用 () => Int 而不仅仅是 Int,否则它没有多大意义。

    这和你想的差不多。编译器生成一个Function0 实例。当您使用Javap 反编译 Scala 代码时,您可以很好地看到这一点。

    另一件值得注意的事情是,每次您在函数中使用 by-name 参数时,都会重新计算生成的 Function0,因此,如果您只想在您想做这样的事情时计算它:

    def callByName(x: => Int) = {
       val a = x
       // do something with a here
    }
    

    Here 是关于整个概念的更多信息。 您还可以在this question 中看到 Scala 如何巧妙地编译按名称参数:

    def getX[T <: X](constr: ⇒ T): Unit = {
        constr
    }
    

    在Java中反编译相当于:

    public <T extends X> void getX(Function0<T> constr) {
        constr.apply();
    }
    

    【讨论】:

      【解决方案2】:

      是的,但是您的示例并不完全正确。如您的问题所述,callByValue 的签名将在调用 callByValue 之前评估 x

      以下内容大致相当于按名称调用:

      def callByValue(x: () => Int) = {
        // same code as above, but all occurrences of x replaced with x()
      }
      

      区别很重要,因为您的callByValue 版本只接受Ints,而不接受返回Ints 的函数。如果您按照将x 替换为x() 的过程,它也不会编译。

      但是是的,=&gt; A 的名称调用参数大致相当于() =&gt; A,只是前者使用起来更方便。我说大致是因为它们不同的类型,它们的应用也略有不同。您可以将() =&gt; A 指定为某事物的类型,但不能指定=&gt; A。当然对于x: () =&gt; A,您必须手动调用x() 而不是x

      【讨论】:

        猜你喜欢
        • 2015-06-07
        • 1970-01-01
        • 1970-01-01
        • 2011-05-21
        • 1970-01-01
        • 2015-05-01
        • 2020-01-05
        • 2013-12-15
        • 1970-01-01
        相关资源
        最近更新 更多