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]
鉴于它会在每次迭代中检查 counter
与 end
,难道不应该改变变量来改变 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:
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.
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.
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.
从测试数据开始:
和运行代码:
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 evaluatesstart
,end
, andstep
. Visual Basic evaluates these values only at this time and then assignsstart
tocounter
. Before the statement block runs, Visual Basic comparescounter
toend
. Ifcounter
is already larger than theend
value (or smaller ifstep
is negative), theFor loop
ends and control passes to the statement that follows theNext
statement. Otherwise, the statement block runs.Each time Visual Basic encounters the
Next
statement, it incrementscounter
bystep
and returns to theFor
statement. Again it comparescounter
toend
, and again it either runs the block or exits the loop, depending on the result. This process continues untilcounter
passesend
or anExit For
statement is encountered. [Emphasis mine]
鉴于它会在每次迭代中检查 counter
与 end
,难道不应该改变变量来改变 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:
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.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.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.