当我一直在学习 Scalag++
时,我经常在读取来自scalac
. 然而,今天我遇到了一些我怀疑即使在g++
宇宙中也会发生的事情。
一位朋友给我发了一个非常简单的代码片段,其中包含一个相当常见的错误:
case class Var(name: String) extends ArithExpr {
override def eval(env: Env) = env.lookup(name) match {
case Some(d) => d
case None => throw new IllegalArgumentException("Env " + env + " does not contain a binding for " + name)
}
override def exprString = name
// } // <-- MISSING THIS BRACE
完整的源文件发布在这里。由于case class Var
类声明缺少右大括号,您会认为编译器会告诉您该声明的左大括号(第 11 行)缺少右大括号。然而,报告它“假设”在前一个声明scalac
的中间缺少一个右括号(在第 7 行)。case class
(完整的错误输出包含在发布的代码的底部。)
如果您了解语言的内部结构,大多数scalac
错误消息都是有意义的,但我在这里完全不知所措。后面的类声明中缺少的右大括号如何最终传播到文件前面已经成功解析的类定义?
您到底是如何向 Scala 初学者解释这一点的?省略右括号正是 Scala 新手通常会犯的错误,但这里的错误消息似乎会让用户误入歧途,因此报告类似的内容可能会更有帮助error: you seem to be missing a '}' somewhere
。
注意:我知道此类问题的通常答案只是“使用 IDE,增量编译会立即标记它”或“语法突出显示应该使这个错误显而易见”——但我的问题是专门询问scalac
输出,所以请请记住,我知道这些是有效的点,但我真的只想了解编译器在这里发生了什么。
更新:
让我尝试一种不同的方法来解释我的困惑。该错误源于缺少右大括号,因此显然是大括号嵌套的问题。将我发布的片段中的文本(代码)转换为一系列行号+大括号对,我们得到:
1{ 4}
6{ 9}
11{ 12{ 15}
19{ 22}
24{ 26}
28{ 33}
我们显然缺少一个右括号。我可以理解scalac
猜测缺少的大括号可能会出现在以下任何一个地方(每个地方都由 表示x
):
1{ 4}
6{ 9}
11{ x 12{ x 15} x <-- HERE OR HERE OR HERE
19{ x 22} x <-- OR HERE OR HERE
24{ x 26} x <-- OR HERE OR HERE
28{ x 33} x <-- OR HERE OR HERE
但是,这就是输出的内容scalac
:
+----- I THINK YOU ARE MISSING A
| CLOSING BRACE RIGHT HERE!
1{ V 4}
6{ x 9}
11{ 12{ 15}
19{ 22}
24{ 26}
28{ 33}
输入的那部分已经很好地嵌套了!在那里添加另一个右括号怎么可能有意义?
编辑:我觉得我应该再次重申我的主要问题:您将如何向 Scala 的新手解释此错误消息(以及如何在源代码中找到错误的根源)?