For start To end Loop with end Variable Changing Mid-Loop

For start To end Loop with end Variable Changing Mid-Loop

从测试数据开始:

和运行代码:

Sub TestLoop()

Dim LastRow As Long, CurRow As Long
LastRow = Range("A" & Rows.Count).End(xlUp).Row

For CurRow = 1 To LastRow
    Range("B" & CurRow).Value = "Done"
    LastRow = 2
Next CurRow

End Sub

我希望循环在第 2 行结束,因为我更改了变量 LastRow。然而结果是:

MSDN Reference FOR VB.NET has this to say:

When a For...Next loop starts, Visual Basic evaluates start, end, and step. Visual Basic evaluates these values only at this time and then assigns start to counter. Before the statement block runs, Visual Basic compares counter to end. If counter is already larger than the end value (or smaller if step is negative), the For loop ends and control passes to the statement that follows the Next statement. Otherwise, the statement block runs.

Each time Visual Basic encounters the Next statement, it increments counter by step and returns to the For statement. Again it compares counter to end, and again it either runs the block or exits the loop, depending on the result. This process continues until counter passes end or an Exit For statement is encountered. [Emphasis mine]

鉴于它会在每次迭代中检查 counterend,难道不应该改变变量来改变 end 吗?

鉴于 Correct MSDN Reference 提到:

The expressions <start-value>, <end-value>, and <step-increment> are evaluated once, in order, and prior to any of the following computations.

看起来 Visual Basic 可以 在循环期间记住 end 的值,即使包含 end 数量的变量发生变化。

基于@Chrismas007 的上述回答,如果您想在 For 结构的范围内使循环短路,您只需将增量变量设置为终止值即可:

For CurRow = 1 To LastRow
    Range("B" & CurRow).Value = "Done"

    ' This will end the loop.
    ' When Next is hit, CurRow will be LastRow + 1.
    CurRow = LastRow

    ' Alternately, you can exit the for loop immediately.
    ' Usually this would be inside an If statement.
    Exit For
Next CurRow

我想在这里说明一些事情。首先,您引用的是 VB.Net 文档。因此,在谈论 VBA 时,我不会依赖于此。事实上,VBA Documentation for the For...Next statement doesn't mention this behavior at all. So, I dug a little deeper and VBA does indeed behave the same as VB.Net here. The following is from the [MS-VBAL]: VBA Language Specification.

The expressions <start-value>, <end-value>, and <step-increment> are evaluated once, in order, and prior to any of the following computations.

这意味着您的示例中的 LastRow 仅在首次进入循环时计算。之后更改它不会影响循环的次数 运行。 (并不是说我建议一开始就尝试这样做。)

这也意味着您也不能更改循环在执行过程中采取的步骤的大小,并且此代码段同时显示了这两者的 "odd" 行为。

Sub TestLoop()

    Dim LastRow As Long, CurRow As Long, StepsToTake As Integer
    LastRow = 100
    StepsToTake = 2

    For CurRow = 1 To LastRow Step StepsToTake
        Range("B" & CurRow).Value = "Done"
        LastRow = 2
        StepsToTake = 1
    Next CurRow

End Sub

对于那些感兴趣的人,这里是 For...Next 语句的整个 运行 时间语义。

Runtime Semantics.

  • The expressions <start-value>, <end-value>, and <step-increment> are evaluated once, in order, and prior to any of the following computations. If the value of <start-value>, <end-value>, and <step-increment> are not Let-coercible to Double, error 13 (Type mismatch) is raised immediately. Otherwise, proceed with the following algorithm using the original, uncoerced values.

  • Execution of the <for-statement> proceeds according to the following algorithm:

    1. If the data value of <step-increment> is zero or a positive number, and the value of <bound-variable-expression> is greater than the value of <end-value>, then execution of the <forstatement> immediately completes; otherwise, advance to Step 2.

    2. If the data value of <step-increment> is a negative number, and the value of <bound-variable-expression> is less than the value of <end-value>, execution of the <for-statement> immediately completes; otherwise, advance to Step 3.

    3. The <statement-block> is executed. If a <nested-for-statement> is present, it is then executed. Finally, the value of <bound-variable-expression> is added to the value of <step-increment> and Let-assigned back to <bound-variable-expression>. Execution then repeats at step 1.

  • If a <goto-statement> defined outside the <for-statement> causes a <statement> within <statement-block> to be executed, the expressions <start-value>, <end-value>, and <step-increment> are not evaluated. If execution of the <statement-block> completes and reaches the end of the <statement-block> without having evaluated <start-value>, <end-value> and <step-increment> during this execution of the enclosing procedure, an error is generated (number 92, "For loop not initialized"). This occurs even if contains an assignment expression that initializes <bound-variable-expression> explicitly. Otherwise, if the expressions <start-value>, <end-value>, and <step-increment> have already been evaluated, the algorithm continues at Step 3 according to the rules defined for execution of a <for-statement>.

  • When the <for-statement> has finished executing, the value of <bound-variable-expression> remains at the value it held as of the loop completion.