如何解释用大括号括起来的函数值(菊石问题)



看完 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. 大括号({}(是函数值的一部分,还是只有函数值(...) => ...?如果是一部分,表单有名称吗?例如,我认为(_ + _)可以称为函数值的占位符语法。

更新:这纯粹是菊石的问题。有关详细信息,请参阅答案。

这里的问题是菊石。

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

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

菊石没有这样的粘贴模式,但它允许您执行多行复制粘贴......但将它们全部包裹在菊石会解开的{}中。所以你的代码:

{ (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 实现的问题。

最新更新