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 不是最佳实践 :)
【问题讨论】:
别这样。写一个实际的Sub
或Function
,然后调用它。您可以轻松预测该行为。你不能对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
。但是,当第二次调用并发出没有GoSub
的Return
时,它会引发运行时错误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 中使用 GoSub
或 GoTo
。这被认为是一种非常糟糕的做法。 GoTo
可用于错误处理,如 On Error GoTo ErrorHandler
。
【讨论】:
循环中的问题是这样的(来自 MSDN 链接):“一个子例程可以包含多个 Return 语句,但遇到的第一个 Return 语句会导致执行流程分支回到该语句紧跟最近执行的 GoSub 语句之后。”如果您GoSub
和 不 Return
,则无法“清除”您当前的 GoSub
上下文。 OP 的代码听起来像是调试和维护的噩梦。
我不得不在答案中写下不好的练习句,sry。
@Comintern - 实际上,“调试和维护的噩梦”通常是许多 VBA 开发人员构建代码的方式。在其中集成了“工作防御”。然后新开发人员在开始使用遗留代码时真的很想哭(我记得我在看到 5 个 subs 和 1 个函数中的 5000 行代码后我想哭。)而且没有文档,因为“我们没有时间做这个和代码本身就是最好的文档”。是的,那里有很多 GoTo 语句。 (免责声明 - 没有反对 OP,很可能情况不同。)
@Vityata:我感觉到你的痛苦。我现在正在经历那个!只是不明白为什么 "developers" 不能只拆分成更小的 functions
或 subs
.. 处理遗留代码很痛苦!
嗯,我希望我帖子中的最后一句话能解决这次谈话,但我想这是不可避免的,哈哈哈。感谢您回答我的问题@Vityata!以上是关于Excel VBA - 使用没有返回的 GoSub的主要内容,如果未能解决你的问题,请参考以下文章
Excel VBA取消输入框不返回false/exit sub