为什么部分应用函数会延迟 Scala 中的类实例化? [英] Why does partially applied function defer class instantiation in Scala?

查看:40
本文介绍了为什么部分应用函数会延迟 Scala 中的类实例化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象一下这段代码:

class Foo {
  println("in Foo")

  def foo(a: Int) = a + 1
}

现在,如果我们调用:

new Foo().foo _

Foo 类的实例将按预期创建:

instance of class Foo will get created, as expected:

in Foo
res0: (Int) => Int = <function1>

但是,如果我们调用它:

However, if we invoke this:

new Foo().foo(_)

Foo 的构造函数不会被调用:

Foo's constructor will not get called:

res1: (Int) => Int = <function1>

如果我们说:

res1(7)

即 Foo 被实例化的时候:

that is when Foo gets instantiated:

in Foo
res2: Int = 8

为什么 Eta 扩展与部分函数应用程序在类实例化方面有所不同?

Why does Eta expansion versus partial function application make a difference in class instantiation?

推荐答案

男孩,这是一个微妙的方案,但据我所知,它遵循了 Scala 规范.我将引用规范的 2.9 版.

Boy, that's a subtle one, but as far as I can tell it's following the Scala spec completely. I'll quote from version 2.9 of the spec.

对于您的第一个示例:正如您所说的那样,您正在通过方法值的特殊情况(第 6.7 节)看到 eta 扩展:

For your first example: as you rightly say, you are seeing eta expansion through a special case of a Method Value (§6.7):

如果 e 是方法类型或者 e 是按名称调用的参数,则表达式 e _ 是格式良好的.如果e是带参数的方法,e_表示e通过eta展开转换为函数类型.

eta 扩展的算法在 §6.26.5 中给出,你可以按照它来替换表达式 new Foo().x1 _:

The algorithm for eta expansion is given in §6.26.5 which you can follow to give the following replacement for the expression new Foo().x1 _:

{
  val x1 = new Foo();
  (y1: Int) => x1.(y1);
}

这意味着当使用 eta 扩展时,所有子表达式都在转换发生的点处进行评估(如果我正确理解了短语最大子表达式"的含义)和最终表达式是匿名函数的创建.

This implies that when eta expansion is being used, all sub-expressions are evaluated at the point where the conversion takes place (if I've understood the meaning of the phrase "maximal sub-expression" correctly) and the final expression is the creation of an anonymous function.

在您的第二个示例中,那些额外的括号意味着编译器将查看 §6.23(特别是匿名函数的占位符语法)并直接创建匿名函数.

In your second example, those extra parentheses mean that the compiler will look at §6.23 (specifically, "Placeholder Syntax for Anonymous Functions) and create an anonymous function directly.

一个表达式(属于语法类别 Expr)可能在标识符合法的地方包含嵌入的下划线符号 _.这样的表达式表示一个匿名函数,其中后续出现的下划线表示连续的参数.

在这种情况下,按照该部分中的算法,您的表达式最终是这样的:

In that case, and following the algorithm in that section, your expression ends up being this:

(x1: Int) => new Foo().foo(x1)

区别很微妙,正如@Antoras 很好地解释的那样,只有在存在副作用代码的情况下才会真正显示出来.

The difference is subtle and, as explained very well by @Antoras, only actually shows in the presence of side-effecting code.

请注意,涉及按名称调用代码块的情况正在修复错误(例如,请参阅这个问题这个错误这个错误).

Note that there is a bugfix under way for the case involving call-by-name code blocks (see, for example, this question, this bug and this bug).

后记:在这两种情况下,匿名函数(x1:Int) =>toto 扩展为

Postscript: In both cases, the anonymous function (x1:Int) => toto gets expanded to

new scala.Function1[Int, Int] {
  def apply(x1: Int): Int = toto
}

这篇关于为什么部分应用函数会延迟 Scala 中的类实例化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆