我一直想知道,在一般情况下,在循环之前声明一个丢弃的变量,而不是在循环内部重复,使任何(性能)差异? Java中的一个(非常无意义的)例子:

A)循环前声明:

double intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

B)声明(重复)内部循环:

for(int i=0; i < 1000; i++){
    double intermediateResult = i;
    System.out.println(intermediateResult);
}

哪个更好,a还是b?

我怀疑重复的变量声明(例b)在理论上会产生更多的开销,但编译器足够聪明,所以这无关紧要。例b的优点是更紧凑,并且将变量的作用域限制在使用它的地方。尽管如此,我还是倾向于根据示例a编写代码。

编辑:我对Java案例特别感兴趣。


当前回答

我认为这取决于编译器,很难给出一个一般的答案。

其他回答

即使我知道我的编译器足够聪明,我也不喜欢依赖它,而是使用a)变体。

b)变体对我来说只有当你迫切需要使intermediateResult在循环体之后不可用时才有意义。但我无法想象这种绝望的情况,无论如何....

编辑:Jon Skeet提出了一个非常好的观点,表明在循环中声明变量可以产生实际的语义差异。

以下是我在。net中编写和编译的内容。

double r0;
for (int i = 0; i < 1000; i++) {
    r0 = i*i;
    Console.WriteLine(r0);
}

for (int j = 0; j < 1000; j++) {
    double r1 = j*j;
    Console.WriteLine(r1);
}

这是我从。net Reflector中得到的,当CIL被渲染回代码时。

for (int i = 0; i < 0x3e8; i++)
{
    double r0 = i * i;
    Console.WriteLine(r0);
}
for (int j = 0; j < 0x3e8; j++)
{
    double r1 = j * j;
    Console.WriteLine(r1);
}

So both look exactly same after compilation. In managed languages code is converted into CL/byte code and at time of execution it's converted into machine language. So in machine language a double may not even be created on the stack. It may just be a register as code reflect that it is a temporary variable for WriteLine function. There are a whole set optimization rules just for loops. So the average guy shouldn't be worried about it, especially in managed languages. There are cases when you can optimize manage code, for example, if you have to concatenate a large number of strings using just string a; a+=anotherstring[i] vs using StringBuilder. There is very big difference in performance between both. There are a lot of such cases where the compiler cannot optimize your code, because it cannot figure out what is intended in a bigger scope. But it can pretty much optimize basic things for you.

我认为b是更好的结构。在a中,intermediateResult的最后一个值在循环结束后保留。

编辑: 这与值类型没有太大区别,但引用类型可能会有些重要。就我个人而言,我喜欢尽快解除对变量的引用以进行清理,b为你做了这件事,

这取决于语言- IIRC c#优化了这一点,所以没有任何区别,但JavaScript(例如)每次都会完成整个内存分配过程。

作为一般规则,我将变量声明在最内部的可能范围内。如果你不在循环外使用intermediateResult,那么我会用B。