先來一堆廢話
最近正在開發(fā)案例模塊包含了多重嵌套循環(huán),于是聽到了下面很有意思的一段對話:
“Gabriel_he:嘿man,有沒有辦法從多重循環(huán)中直接跳出的方法。
HoldTheBabyToGoToSchool:好像沒得,只能挨著判斷。
Gabriel_he:噢,其實可以用goto語句。
HoldTheBabyToGoToSchool:goto語句老師不是說不要使用啊。
Gabriel_he:那是對于大學生或者菜鳥程序員是這樣的,對于那些5、10年的老司機來說完全不是問題,問題是看你怎么用它。”
我在旁邊默默想了想好像是這么回事,大一上C語言課程的時候就接觸到GOTO語句,依稀記得老師也是告訴我們GOTO語句會造成程序的混亂,可讀性不強,是個壞習慣,寫法又爛,最好不要使用。這個問題從我接觸到GOTO的第一天起就沒有想清楚過,或許根本沒有花心思去想,直到聽到上面的對話,讓我又重新燃起對GOTO語句了解的欲望。
什么是GOTO?
GOTO語句也稱為無條件轉(zhuǎn)移語句,其一般格式如下:
(語句標號)loop:for(i=0;i<10;i++){
//todo
}
goto loop;
GOTO語句的語義是改變程序流向, 轉(zhuǎn)去執(zhí)行語句標號所標識的語句。
該不該使用?
在整個編程語言發(fā)展的過程中,對goto語句到底該不該使用,一直都是眾說紛紜,大致可以分為以Donald Ervin Knuth為首的支持派(GOTO語句使用起來比較靈活,而且有些情形能提高程序的效率。若完全刪去GOTO語句,有些情形反而會使程序過于復雜,增加一些不必要的計算量。)和以Edsger Wybe Dijkstra為首的反對派(GOTO語句使程序的靜態(tài)結(jié)構(gòu)和動態(tài)結(jié)構(gòu)不一致,從而使程序難以理解,難以查錯。), 后者在一封信中指出Go To Statement Considered Harmful。
直到1974年,D·E·克努斯對于GOTO語句爭論作了全面公正的評述,其基本觀點是:不加限制地使用GOTO語句,特別是使用往回跳的GOTO語句,會使程序結(jié)構(gòu)難于理解,在這種情形,應盡量避免使用GOTO語句。但在另外一些情況下,為了提高程序的效率,同時又不至于破壞程序的良好結(jié)構(gòu),有控制地使用一些GOTO語句也是必要的。
后來,G·加科皮尼和C·波姆從理論上證明了:任何程序都可以用順序、分支和重復結(jié)構(gòu)表示出來。這個結(jié)論表明,從高級程序語言中去掉GOTO語句并不影響高級程序語言的編程能力,而且編寫的程序結(jié)構(gòu)更加清晰。
場景分析
-
多重循環(huán)跳出問題
由于不同的編程語言對GOTO語句的支持情況不同,下面只以C#進行舉例:
for(int i=0;i<10;i++)
{
for (int j=0;j<5;j++)
{
//todo 直接跳出整個嵌套循環(huán)
}
}方法一: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
在我們的實際工作中經(jīng)常會有對于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語句的場景,大多數(shù)高級語言都自帶垃圾回收機制,不用開發(fā)者去考慮資源的回收和釋放,換句話說現(xiàn)在的高級程序語言能夠找到很好的替代方案,即使在某些情況下代碼沒有那么優(yōu)雅,但是它能夠保證程序的可靠性和可讀性。
在操作系統(tǒng)或底層硬件開發(fā)上,有些使用的C或者匯編,在某些場景下使用GOTO效率還會更高,同時像匯編沒有if-else,while,都是有條件和無條件轉(zhuǎn)移,那么開發(fā)者對goto的使用自然了熟于心經(jīng)驗使然。
總之,GOTO語句盡量少用,大多數(shù)情況下都是可以通過結(jié)構(gòu)化編程方式解決問題,即便你或你的團隊非要使用需要在初期明確使用的標準(在同一個函數(shù)中轉(zhuǎn)移,保證是順序執(zhí)行等)和場景并添加相應的注釋。