先来一堆废话
最近正在开发案例模块包含了多重嵌套循环,于是听到了下面很有意思的一段对话:
“Gabriel_he:嘿man,有没有办法从多重循环中直接跳出的方法。
HoldTheBabyToGoToSchool:好像没得,只能挨着判断。
Gabriel_he:噢,其实可以用goto语句。
HoldTheBabyToGoToSchool:goto语句老师不是说不要使用啊。
Gabriel_he:那是对于大学生或者菜鸟程序员是这样的,对于那些5、10年的老司机来说完全不是问题,问题是看你怎么用它。”
我在旁边默默想了想好像是这么回事,大一上C语言课程的时候就接触到GOTO语句,依稀记得老师也是告诉我们GOTO语句会造成程序的混乱,可读性不强,是个坏习惯,写法又烂,最好不要使用。这个问题从我接触到GOTO的第一天起就没有想清楚过,或许根本没有花心思去想,直到听到上面的对话,让我又重新燃起对GOTO语句了解的欲望。
什么是GOTO?
GOTO语句也称为无条件转移语句,其一般格式如下:
(语句标号)loop:for(i=0;i<10;i++){
//todo
}
goto loop;
GOTO语句的语义是改变程序流向, 转去执行语句标号所标识的语句。
该不该使用?
在整个编程语言发展的过程中,对goto语句到底该不该使用,一直都是众说纷纭,大致可以分为以Donald Ervin Knuth为首的支持派(GOTO语句使用起来比较灵活,而且有些情形能提高程序的效率。若完全删去GOTO语句,有些情形反而会使程序过于复杂,增加一些不必要的计算量。)和以Edsger Wybe Dijkstra为首的反对派(GOTO语句使程序的静态结构和动态结构不一致,从而使程序难以理解,难以查错。), 后者在一封信中指出Go To Statement Considered Harmful。
直到1974年,D·E·克努斯对于GOTO语句争论作了全面公正的评述,其基本观点是:不加限制地使用GOTO语句,特别是使用往回跳的GOTO语句,会使程序结构难于理解,在这种情形,应尽量避免使用GOTO语句。但在另外一些情况下,为了提高程序的效率,同时又不至于破坏程序的良好结构,有控制地使用一些GOTO语句也是必要的。
后来,G·加科皮尼和C·波姆从理论上证明了:任何程序都可以用顺序、分支和重复结构表示出来。这个结论表明,从高级程序语言中去掉GOTO语句并不影响高级程序语言的编程能力,而且编写的程序结构更加清晰。
场景分析
-
多重循环跳出问题
由于不同的编程语言对GOTO语句的支持情况不同,下面只以C#进行举例:
for(int i=0;i<10;i++)
{
for (int j=0;j<5;j++)
{
//todo 直接跳出整个嵌套循环
}
}方法一:goto for(int i=0;i<10;i++) { for (int j=0;j<5;j++) { goto:finish; } } finish:Console.WriteLine('End The Loop'); 方法二:flag,教条式写法 bool flag=false; for(int i=0;i<10;i++) { for (int j=0;j<5;j++) { flag=true; break; } if(flag) { break; } } 大家看了上面两种写法后还有没有可能想出其他的方法,下面我来给出第三种比较风骚的写法(纯属搞来耍) 方法三: try { for(int i=0;i<10;i++) { for (int j=0;j<5;j++) { throw new Exception(); } } } catch(Exception ex) { Console.WriteLine('太骚了'); } 在JAVA、Javascript(goto为保留关键字)里没有提供goto语句,但是可以通过标签(我个人理解为受限制的GOTO语句)的写法达到GOTO语句的效果。 loop:for (var i=0;i<10;i++) { for(var j=0;j<5;j++) { break loop; } }
关于if-else
在我们的实际工作中经常会有对于if-else的以下使用场景:
if(doSomething())
{
if(doSomething1())
{
if(doSomething2())
{
.......
}
}
else
{
}
}
else
{
}
那么对于以上这种情况,我们是否可以考虑GOTO语句在多重条件判断下使用呢?下面看看使用GOTO语句的方式
if(!doSomething())
{
goto error;
}
if(!doSomething1())
{
goto error;
}
........
是不是明显要清晰很多
感受
GOTO语句的使用还需要回归到具体场景,具体团队中去,不要偏激的认为GOTO语句完全不能使用或者一看到GOTO语句就认为这个代码太垃圾,也不要认为用了GOTO语句的代码就是好味道。
就拿我们来说,除了上面的两种方式外我还真没想到需要使用GOTO语句的场景,大多数高级语言都自带垃圾回收机制,不用开发者去考虑资源的回收和释放,换句话说现在的高级程序语言能够找到很好的替代方案,即使在某些情况下代码没有那么优雅,但是它能够保证程序的可靠性和可读性。
在操作系统或底层硬件开发上,有些使用的C或者汇编,在某些场景下使用GOTO效率还会更高,同时像汇编没有if-else,while,都是有条件和无条件转移,那么开发者对goto的使用自然了熟于心经验使然。
总之,GOTO语句尽量少用,大多数情况下都是可以通过结构化编程方式解决问题,即便你或你的团队非要使用需要在初期明确使用的标准(在同一个函数中转移,保证是顺序执行等)和场景并添加相应的注释。