充分了解关于使用GOTO(GOTO still considered harmful?)是否是良好做法的永恒讨论,我在这里要问的是,是否有一些使用GOTO时的缺点,特别是在CMD / DOS shell中。
缺点我的意思是,如果有一些性能损失或某些情况下广泛使用GOTO可能最终终止我的脚本(如后面描述的行为)。我知道,因为TI-BASIC没有很好的方法来创建没有它的结构化程序,在该平台中重复使用GOTO最终会耗尽内存。 TIBasicDev的以下引用解释了这种行为:
使用Goto退出需要End命令的任何代码块会导致内存泄漏,在程序完成运行或执行Return命令之前无法使用,这会降低程序速度。
在CMD中循环执行命令的另一种“方式”是通过FOR语句,这些语句对于它们的预期参数非常具体,因此不能在任何情况下使用。
答案 0 :(得分:2)
Windows批处理脚本中的GOTO通常可以安全使用,有时也是必需的。但是有三个非直观的设计特征值得注意:
1)不要在带括号的代码块中放置标签
你可以在一个带括号的块中放置一个标签,但它可能不会给你想要的结果。例如,FOR循环DO块中的GOTO将立即终止循环。如果GOTO引用DO块中的标签,则控件被正确传送到标签位置,但批量解析器现在对FOR循环上下文一无所知。代码将被执行,就好像它不在循环中一样。有关详细信息,请参阅(Windows batch) Goto within if block behaves very strangely的已接听答案。
2)标签的位置会影响效果。
除非您正在处理非常大的脚本,否则这通常不是问题。
执行GOTO :label
(或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
虽然标签的重复使用有效,但这不是一个好习惯,因为它可能会混淆试图解释或调试脚本的其他任何人。
答案 1 :(得分:1)
GOTO :label
是批处理编码不可或缺的一部分,没有内置的缺点 - 它是批处理脚本的必要部分。