還記得當年老師不讓你使用的GOTO語句嗎?

先來一堆廢話

最近正在開發(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í)行等)和場景并添加相應的注釋。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容