【问题标题】:Does for loop parameters execute each iteration?for 循环参数是否执行每次迭代?
【发布时间】:2015-05-02 04:46:42
【问题描述】:

在某些时候,我想随机化一个数组在创建时是否会反转。

我想到的第一件事是:

bool reverse = Random.value > 0.5f;
for (
        int i = reverse ? steps - 1 : 0; 
        reverse ? i >= 0 : i < steps; 
        i += reverse ? -1 : +1
    ) {
    rotateScript.angles.Add(angleRange[0] + stepAdder * i);
}

后来我意识到,尽管需要更多的行,但 if/else 中的两个 for 循环会更具可读性。

但问题仍然存在:这些三元条件会在每次迭代中执行一次,还是只执行一次?

【问题讨论】:

    标签: c# performance for-loop parameters reverse


    【解决方案1】:

    正确,for 语句的第 2 和第 3 个组件在每次迭代中都会进行评估。

    这个:

    for( x; y; z ) a;
    

    相当于:

    x;
    while( y ) { a; z; }
    

    因此,y 的评估次数将比 z 多 1 次。

    【讨论】:

    • 谢谢。我以为编译器可能会在参数内做一些工作,但现在我发现它做不到,因为我显然可以在循环范围内更改“反向”布尔值的值。
    【解决方案2】:

    正如@Dai 指出的,第二和第三条语句必须在每次迭代结束时进行评估。

    此行为在 C# 语言规范的§8.8.3 中有详细说明。解释一下,它说的是一个

    for ( initialiser; condition; iterator; ) { ... }
    

    声明:

    for 语句的执行如下:

    • 如果存在 for 初始化程序,变量初始化程序或语句表达式将按照它们的写入顺序执行。此步骤只执行一次。
    • 如果存在 for 条件,则会对其进行评估。
    • 如果 for 条件不存在或评估结果为真,则控制权将转移到嵌入语句。当控制到达嵌入语句的终点时,for-iterator 的表达式将依次计算,然后执行另一次迭代,从上述步骤中的 for-condition 计算开始。
    • 如果存在 for 条件并且评估结果为 false,则控制权将转移到 for 语句的终点。

    使用您的代码

    for (
        int i = reverse ? steps - 1 : 0; 
        reverse ? i >= 0 : i < steps; 
        i += reverse ? -1 : +1
    ) {
        rotateScript.angles.Add(angleRange[0] + stepAdder * i);
    }
    

    您确实有一些选项可以使到达迭代时的三元运算符变得不必要。

    您提到使用带有两个for 循环的if/else,但我建议您不要这样做,因为它会重复代码,这会妨碍其可维护性和可读性。


    选项 1:使用标准 for 循环:

    您可以将逻辑放入循环中的代码,即

    for ( i = 0; i < steps; i += 1 )
    {
        int multiplier = reverse ? steps - 1 - i: i;
        rotateScript.angles.Add(angleRange[0] + stepAdder * multiplier);
    }
    

    选项 2:将三元逻辑移出:

    计算极限和增量,即

    int start = reverse ? steps - 1 : 0;
    int increment = reverse ? -1 : +1;
    int limit = reverse ? -1 : steps;
    
    for ( int i = start; i != limit; i += increment; )
    {
        rotateScript.angles.Add(angleRange[0] + stepAdder * i);
    }
    

    我更喜欢选项 1,因为我认为大多数人都觉得简单的 for 循环更容易理解。

    【讨论】:

    • 我确实喜欢选项 1,确实比带有两个循环的 if/else 更好。非常好的答案,谢谢!
    • 没问题 - 很高兴能帮上忙!另外,非常感谢您接受我的回答! :)