美文网首页Swartz动物园程序员unity3D技术分享
还记得当年老师不让你使用的GOTO语句吗?

还记得当年老师不让你使用的GOTO语句吗?

作者: 余鹏飞 | 来源:发表于2016-12-17 20:10 被阅读921次

先来一堆废话

最近正在开发案例模块包含了多重嵌套循环,于是听到了下面很有意思的一段对话:

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语句尽量少用,大多数情况下都是可以通过结构化编程方式解决问题,即便你或你的团队非要使用需要在初期明确使用的标准(在同一个函数中转移,保证是顺序执行等)和场景并添加相应的注释。

相关文章

网友评论

  • 多了去的YangXuLei:我大一的时候写C就喜欢goto,跳来跳去,各种灵活方便,就像我鬼魅的步伐和轻盈灵活的身姿,和着键盘声飞跃我的思维,写的程序被驳回过就因为goto
  • 残破的遗迹:说得好,Java没有goto好多事情就尴尬了

本文标题:还记得当年老师不让你使用的GOTO语句吗?

本文链接:https://www.haomeiwen.com/subject/qwgomttx.html