在 for 循环声明中初始化的变量的范围实际上不仅仅是块范围吗?

Is the scope of a variable initialized in a for loop declaration actually more than just block scope?

考虑一个带有计数器的 for 循环:

for (int i = 0; i < 100; i++ /* `i` is visible here */) {
    /* `i` is visible here */
}
/* `i` not visible here */

一切顺利。 We say that i has "block" scope.

但是,为什么在 for 循环中声明的变量在 i++ 中不可访问?

例如,为什么 j 不在此处的范围内,而它也有 "block" 范围并且是在 i += j 之前的时间段内声明的?

for (int i = 0; i < 100; i += j /* only `i` is visible here */) {
    int j = 1;
    /* `i` and `j` are visible here */
}
/* `i` and `j` are not visible here */

我见过很多关于 i 范围的问题,但没有看到任何关于 for 循环括号内的 j 范围的问题。这是否意味着在技术上还有另一个没有人谈论的范围是 "for-loop declaration scope"?如果是这样,我感兴趣的是这个范围在 Java 或 C# 等规范中是如何定义的,以及它通常被程序员称为什么范围。

编辑:是的,我知道我可以将循环声明为 for (int j, i = 0; i < 100; i += j),但这仍然表明 for 循环声明比它们的大括号具有更高的范围。

变量 J 在 declaration/initialization 之前引用。当第一次执行循环时,JVM 不会引用它。

您已在循环内初始化变量 j。

我希望这能解决您的问题。

第一个作用域以 void main{ } 开始,而不是在其他内部块之后,例如您的 for 循环作用域,并且用第一个块声明的所有变量对所有内部作用域块都是可见的,我们must declared variable before use it(在你的例子中是变量j)你在for循环中使用了变量而没有声明它,所以不可能在声明之前使用它并且我们的光标由于从上到下到达for循环首先逐行处理它检查变量是否已声明?

一个很有趣的问题。你提出了一个很好的观点,如果你从运行时的角度来看 j 应该是可见的,因为在迭代之后调用增量表达式。

但是从编译器的角度来看,当它读取 for 循环语句时,即 (int i = 0; i < 100; i += j),它会期望 j 已经被声明。

我想你可以说与 i 和 j 都有的块作用域相比,i 有一个额外的语句作用域。

JLS 6.3 以这种方式指定范围的表面原因:

The scope of a local variable declared in the ForInit part of a basic for statement (§14.14.1) includes all of the following:

  • Its own initializer
  • Any further declarators to the right in the ForInit part of the for statement
  • The Expression and ForUpdate parts of the for statement
  • The contained Statement

"contained statement" for body。 for body 中定义的变量没有特殊的作用域规则。正常规则适用。 (它们也在 JLS 6.3 中。)


这种语言设计背后的原因包括(我猜1)如下:

  • 如果您必须在循环 body 中查看变量 声明的 那里的 2,那么可读性会很差。
  • 判断循环中声明的变量是否确实初始化的逻辑很难具体说明,程序员也很难理解。示例:

    for (i = 1; i < 10; i = i + j) {
        int j;
        if (i > 3) {
            j = 42;
        }
        // do stuff
    }
    

1 - 真正的原因只有在 1970 年代的 C 语言的设计者才知道。我怀疑 Java 设计师是否考虑过与 C 不同的做法。他们试图让 Java "C-like".

2 - 循环 body 中的某些内容可以修改循环变量已经够糟糕了。 :-(