Excel VBA - 使用没有返回的 GoSub

Posted

技术标签:

【中文标题】Excel VBA - 使用没有返回的 GoSub【英文标题】:Excel VBA - Using GoSub without Return 【发布时间】:2018-10-08 15:11:46 【问题描述】:

我有一种情况,我想在子例程中使用 GoSub,并在 某些 情况下返回,但在其他情况下,我希望 让它返回。这将是一个很大的 For Loop 和 GoSub without Return 可能会发生数百次。如果我不返回,这会在内存中累积并导致任何问题吗?

我想我的问题归结为:GoSub 堆栈吗?大量未退回的 GoSub 是否会导致问题?

如果它确实堆栈,我可以更改代码以在我不想返回的情况下使用 GoTo,但为简单起见,我宁愿不这样做。

还要提前感谢您没有向我讲授 GoTo/GoSub 不是最佳实践 :)

【问题讨论】:

别这样。写一个实际的SubFunction,然后调用它。您可以轻松预测该行为。你不能GoSub做同样的事情正是不使用它的原因。 【参考方案1】:

正如许多其他人所说:不要这样做。我现在(以谋生为生)编程已经 30 年了,从来不需要使用 GoSub/Return,除非在编程语言不提供任何子例程时作为替代。

也就是说 - 我很好奇 VBA 如何处理这个问题。第一件事:我假设必须有一种堆栈。您可以在一个例程中有多个 GoSub/Return 并且处理正确:

Sub testSub1()
    Call StrangeRoutine1
End Sub

Sub StrangeRoutine1()

    GoSub L1
    Exit Sub

L1:
    Debug.Print "Strange1 - L1a"
    GoSub L2
    Debug.Print "Strange1 - L1b"
    Return

L2:
    Debug.Print "Strange1 - L2a"
    Return
End Sub

这个打印:

Strange1 - L1a
Strange1 - L2a
Strange1 - L1b

所以return 语句在正确的GoSub 之后跳转——这肯定是用一种堆栈处理的。

但是,似乎一旦离开子例程,该堆栈就会被清除。以下例程有GoSub,但没有Return。所以它在“堆栈”上留下了一个开放的GoSub。但是,当第二次调用并发出没有GoSubReturn 时,它会引发运行时错误3“Return without GoSub`。

Dim count As Long

Sub testSub2()
    For count = 1 To 2
        Call StrangeRoutine2
    Next
End Sub


Sub StrangeRoutine2()
    If count > 1 Then Return
    GoSub L1
    Exit Sub

L1:
    Debug.Print "Strange2 - L1"
End Sub

P.S.:我有没有提到它:不要这样做!

【讨论】:

我怀疑“堆栈”的范围仅限于过程,因为这两个指令都需要在同一个过程中。如果是这样(并且允许跳入和跳出过程),您可能最终会破坏 real 堆栈。 啊哈!然后它确实堆叠了,好的,谢谢。我已经在不使用 Return 的情况下运行 GoSub 50,000 次,然后在不调用其他 GoSub 的情况下使用 Return 10,000 次并且每次 Return 都成功进行了自己的测试。只要调用 Return 的次数不超过调用 GoSub 的次数,它似乎就可以正常工作,并且不会引起任何问题。我的用例将更像是 1,000 最大值,所以我的 50,000 测试表明它可以正常工作 - 即使它不是最佳实践;) 您可以使用Foo: GoSub Foo 轻松确认这一点,这会导致运行时错误 28 - Out of stack space。【参考方案2】:

在 VBE 中查看堆栈的快捷键是 Ctrl+E。如您所见,它不会堆叠:

Sub GosubDemo()

    GoSub MyRoutine
    Debug.Print "Line before Exiting"
    Exit Sub

GoSomeWhereElso:
    Debug.Print "SomewhereElso I am "
    Return

MyRoutine:
    Debug.Print "My routine"
    GoSub GoSomeWhereElso
    Return

End Sub

但是,不要在 VBA 中使用 GoSubGoTo。这被认为是一种非常糟糕的做法。 GoTo 可用于错误处理,如 On Error GoTo ErrorHandler

GoSub ... Return MSDN Dijkstra - GoTo considered harmful

【讨论】:

循环中的问题是这样的(来自 MSDN 链接):“一个子例程可以包含多个 Return 语句,但遇到的第一个 Return 语句会导致执行流程分支回到该语句紧跟最近执行的 GoSub 语句之后。”如果您 GoSub Return,则无法“清除”您当前的 GoSub 上下文。 OP 的代码听起来像是调试和维护的噩梦。 我不得不在答案中写下不好的练习句,sry。 @Comintern - 实际上,“调试和维护的噩梦”通常是许多 VBA 开发人员构建代码的方式。在其中集成了“工作防御”。然后新开发人员在开始使用遗留代码时真的很想哭(我记得我在看到 5 个 subs 和 1 个函数中的 5000 行代码后我想哭。)而且没有文档,因为“我们没有时间做这个和代码本身就是最好的文档”。是的,那里有很多 GoTo 语句。 (免责声明 - 没有反对 OP,很可能情况不同。) @Vityata:我感觉到你的痛苦。我现在正在经历那个!只是不明白为什么 "developers" 不能只拆分成更小的 functionssubs.. 处理遗留代码很痛苦! 嗯,我希望我帖子中的最后一句话能解决这次谈话,但我想这是不可避免的,哈哈哈。感谢您回答我的问题@Vityata!

以上是关于Excel VBA - 使用没有返回的 GoSub的主要内容,如果未能解决你的问题,请参考以下文章

Excel VBA取消输入框不返回false/exit sub

返回数组Excel VBA中元素的索引

有没有办法在没有 VBA 的情况下在 Excel 中连接两个数组? [复制]

使用EXCEL vba下载文件时出现问题

将命名范围值分配给变量(Excel VBA) - 新手

使用 Excel VBA 从公式返回 ABS 值