【问题标题】:How to go to next iteration on error AKA simulating Python's "continue" statement in VBA?如何在 VBA 中模拟 Python 的“继续”语句的错误 AKA 中进行下一次迭代?
【发布时间】:2019-03-22 06:22:25
【问题描述】:

在以下代码中,如何在遇到错误后使循环在下一次迭代中继续 - 而不是下一行?

现在代码不会超过 x=0:

Sub skip_iteration()

Dim x As Long

For x = 5 To -5 Step -1
    On Error GoTo errhandler:
    Debug.Print 15 / x
    Debug.Print "I don't want this to be printed on error"
Next x

errhandler:
If Err.Number = 11 Then
    Debug.Print ("Error on " & x)
End If

End Sub

我已经研究了这个答案: Skip to next iteration in loop vba 等,但无法将其转换为我的代码。

【问题讨论】:

  • 我喜欢你的简历
  • @QHarr - Resume 将导致无限循环。错误处理程序中的Resume Next 是正确的处理方式。
  • @Vityata 正确。我的意思是在错误处理程序中。在这种情况下,Resume 和 Resume Next 有区别吗?原谅我的无知。 + 为您的解决方案。
  • @QHarr - 我知道(对于错误处理程序)。那里的Resume 会导致死循环。
  • @QHarr - 实际上,来自错误处理程序的这两个Resume NextResume 确实是一个有用的功能。我已经更新了示例。

标签: excel vba


【解决方案1】:

您需要Resume Next 才能转到该行之后的下一行,从而导致错误。 Err.Clear 也是一个很好的做法。

errhandler 之前的Exit Sub 也是一个很好的做法:

Sub SkipIteration()

    Dim x As Long        
    For x = 5 To -5 Step -1
        On Error GoTo errhandler:
        Debug.Print 15 / x
        Debug.Print "testing"
    Next x        
    Exit Sub

errhandler:
    If Err.Number = 11 Then
        Debug.Print ("Error on " & x)
        Err.Clear
        Resume Next
    End If    
End Sub

ResumeResume Next 的区别如下:

  • Resume 试图回到它被调用的地方。

TestMeResume 过程中,它在 Debug.Print a/b 处引发错误 11,并在错误处理程序中分配 b = 5。然后使用Resume 重试Debug.Print a / b,并一直到@ 987654332@ 不是0,它运行。

  • Resume Next 转到调用它的位置,忽略该行并继续下一个。

TestMeResumeNext 过程中,在a = 12 处引发错误91,并触发错误处理程序。在错误处理程序中,a 被分配给Range("A14"),而Resume Next 则跳过a = 12 并继续Sub


Sub TestMeResumeNext()

    On Error GoTo TestMeResumeNext_Error

    Dim a As Range
    a = 12              'Error 91 here!
    Debug.Print a.Row   'Resume Next goes back here
    Exit Sub

TestMeResumeNext_Error:
    Set a = Range("A14")
    Resume Next
End Sub

Sub TestMeResume()

    On Error GoTo TestMeResume_Error

    Dim a As Long: a = 10
    Dim b As Long: b = 0
    Debug.Print a / b   'Error 11 here the first time
    Exit Sub

TestMeResume_Error:
    b = 5
    Resume
End Sub

【讨论】:

  • Vityata,非常感谢您的彻底回答。但是,正如我在问题中所说,我想跳到下一次迭代,而不是下一行。在您的代码中,Resume Next 将转到 Debug.Print "testing",我想跳过它 - 以及后面可能发生的任何事情 - 而是转到 Next x
  • @barciewicz - 我明白了。我想出了另一个答案,GoTo 有点糟糕,危险等等。
【解决方案2】:

这里的另一个选项是内联您的错误处理程序。这使您清楚地意识到特定代码行可能引发错误,并且不依赖Resume 进行流控制。让错误转到函数底部的处理程序,然后跳回代码的主行,这使得循环的预期行为变得不那么明显了。

Sub SkipIteration()
    Dim x As Long

    For x = 5 To -5 Step -1
        On Error Resume Next
        Debug.Print 15 / x
        If Err.Number = 11 Then
            Debug.Print "Expected error on " & x
            On Error GoTo errhandler
        Else
            On Error GoTo errhandler
            Debug.Print "Process the rest of the loop"
        End If
    Next x

    Exit Sub
errhandler:
    Debug.Print "Unexpected error "; Err.Number
End Sub

更好的办法是将程序的关注点分开,使执行的循环部分是一条语句:

Sub SkipIteration()
    On Error GoTo errhandler

    Dim x As Long
    For x = 5 To -5 Step -1
        If TheThingThatCanError(x) Then
            ActionThatDependsOnAbove x
        End If
    Next x

    Exit Sub
errhandler:
    Debug.Print "Unexpected error "; Err.Number
End Sub

Private Function TheThingThatCanError(x As Long) As Boolean
    On Error Resume Next
    Debug.Print 15 / x
    If Err.Number = 11 Then
        Debug.Print "Expected error on " & x
        Exit Function
    End If
    TheThingThatCanError = True
End Function

Private Sub ActionThatDependsOnAbove(x As Long)
    Debug.Print "I don't want this to be printed on error " & x
End Sub

【讨论】:

    【解决方案3】:

    如果您想跳过Error 并继续下一次迭代,一种可能的方法是使用GoTo 并制作一些spaghetti code

    Sub SkipIteration()
        Dim x As Long
        For x = 5 To -5 Step -1
            If IsError(Evaluate("15 / " & x)) Then GoTo Skipper
            Debug.Print 15 / x
            Debug.Print x
    Skipper:
        Next x
    End Sub
    

    或者在 if 中使用嵌入整个 IsError 并避免 GoTo。但是你必须向右移动一个标签并失去缩进:

    Sub SkipIteration()
        Dim x As Long
        For x = 5 To -5 Step -1
            If Not IsError(Evaluate("15 / " & x)) Then
                Debug.Print 15 / x
                Debug.Print x
            End If
        Next x
    End Sub
    

    【讨论】:

    • 像这样使用Evaluate 太可怕了。它不仅对表达式求值两次(一次用于 Evaluate 调用,一次用于“真实”调用),它会将其卸载到 Excel,它可能会或可能不会对更复杂的表达式使用相同的语义。
    • @Comintern - 是的,不是最好的,但目前无法提出单行选项。而且我不想有专门的功能或On Error Resume Next,因为这就像你的答案。 :D
    猜你喜欢
    • 1970-01-01
    • 2018-07-24
    • 2010-12-23
    • 1970-01-01
    • 2014-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多