6

阅读Scala 中大括号和圆括号之间的形式区别是什么,什么时候应该使用它们?,我仍然不知道如何理解 . 包裹的函数值{}

考虑以下两个 REPL 会话:

@ val f = { (x: Int) =>
    x
    val y = x
    y
  }
f: Int => Int = ammonite.$sess.cmd30$$$Lambda$1765/0x0000000801346840@24c7b944
@ { (x: Int) =>
    x
    val y = x
    y
  }
cmd31.sc:3: not found: value x
  val y = x
          ^
Compilation Failed

我有几个问题。

  1. 为什么第一个片段编译而第二个不编译?在第一个片段中,编译器知道{...}作为一个整体是一个函数值。在第二个片段中,只有(x: Int) => \n x部分是函数值(对不起\n,表示换行符)。为什么?
  2. 关于{ (x: Int) => \n ... },它什么时候被解释为函数值,什么时候不是?
  3. 花括号 ( {}) 是函数值的一部分,还是仅(...) => ...在函数值内部?如果它是它的一部分,表格是否有名称?例如,我认为(_ + _)可以称为函数值的占位符语法。

更新:这纯粹是一个菊石问题。详情见答案。

4

1 回答 1

4

这里的问题是菊石。

Scala REPL 有一个粘贴模式,允许您在评估之前粘贴多行:

:paste
sealed trait X
class Implementation extends X // impossible without doing it at once
// Ctrl+D

Ammonite 没有这种粘贴模式,但它允许您执行多行复制粘贴......但是将它们全部包裹起来{},ammonite 将在其中展开。所以你的代码:

{ (x: Int) =>
  x
  val y = x
  y
}

编译器将其视为

(x: Int) =>
  x // end of function definition
val y = x // new variable calling x, which isn't defined anywhere
y // call to undefined y, because previous line failed

第一个示例之所以有效,是因为您的val f = ammonite 解析器无法假定您的所有代码都在一个块内,因此在将其传递给编译器之前它不会将其剥离。

正如文档建议的那样,如果您不想要这种行为,您应该添加另一层大括号:

{{ (x: Int) =>
  x
  val y = x
  y
}}

这不是编译器和语言规范问题,而是某些特定 REPL 实现的问题。

于 2020-06-24T09:33:34.240 回答