0

充分了解关于使用 GOTO是否是好习惯的永恒讨论( GOTO 仍然被认为是有害的?),我想在这里问的是使用 GOTO 是否有一些缺点,特别是在 CMD/DOS shell 中。

我所说的缺点是指如果性能下降或在某些情况下大量使用 GOTO 可能最终终止我的脚本(如稍后描述的行为)。我知道,因为没有它 TI-BASIC 没有创建结构化程序的好方法,所以在该平台上重复使用 GOTO 最终会耗尽内存。TIBasicDev的以下引用解释了这种行为:

使用 Goto 退出任何需要 End 命令的代码块会导致内存泄漏,在程序完成运行或执行 Return 命令之前无法使用,这会减慢程序的速度。

在 CMD 中循环命令的另一种“方式”是通过 FOR 语句,这些语句非常具体地说明了它们的预期参数,因此不能在任何情况下使用。

4

2 回答 2

3

Windows 批处理脚本中的 GOTO 通常可以安全使用,有时是必要的。但是有三个非直观的设计特征值得注意:

1) 不要 GOTO 放置在带括号的代码块中的标签

您可以 GOTO 放置在带括号的块中的标签,但它可能不会给您想要的结果。例如, FOR 循环 DO 块中的 GOTO 将立即终止循环。如果 GOTO 引用 DO 块中的标签,则控制正确地转移到标签位置,但批处理解析器现在对 FOR 循环上下文一无所知。代码将像不在循环内一样执行。有关更多信息,请参阅if 块行为非常奇怪的(Windows 批处理)Goto的公认答案。

2) 标签的位置会影响性能。

除非您正在处理一个非常大的脚本,否则这通常不是问题。

执行GOTO :label(or CALL :label) 时,批处理器从当前脚本位置开始扫描,查找:label. 如果它在没有找到标签的情况下到达文件的末尾,那么它会循环回到顶部并继续搜索。如果到达起点而没有找到标签,则会引发错误。因此,有时可以通过构建脚本使标签在它们各自的 GOTO(或 CALL)之后不久出现来提高非常大的脚本的性能。当然,如果从许多位置引用标签,那可能是不可能的。

3) 同一个标签实际上可以在多个位置安全使用(不建议)

一旦您了解了上面第 2 点中描述的标签扫描过程,如果您小心的话,您可以安全地重复使用标签。

例如,以下脚本将正常工作:

@echo off

for %%A in (1 2 3 X Y Z) do (
  echo %%A
  if %%A equ 3 goto break
)
:break

for %%A in (A B C 8 9 10) do (
  echo %%A
  if %%A equ C goto break
)
:break

- 输出 -

1
2
3
A
B
C

尽管重用标签有效,但这不是一个好的做法,因为它可能会使任何试图解释或调试脚本的人感到困惑。

于 2013-10-27T17:38:41.090 回答
1

GOTO :label是批处理编码的一个组成部分并且没有内置的缺点 - 它是批处理脚本的必要部分。

于 2013-10-27T14:23:32.010 回答