代码之家  ›  专栏  ›  技术社区  ›  Your Common Sense

goto和throw的区别?

  •  6
  • Your Common Sense  · 技术社区  · 14 年前

    最近很多人指责我只提到一个词——“goto”。
    这让我纳闷,为什么它被认为是一个如此下流的词。
    我知道之前有几次关于这个话题的讨论,但这并不能使我信服。 ome of the answers just says "it's bad" not even trying to explain 有些带来 reasons, irrelevant for scripting languages like PHP, IMO .

    无论如何,我要问一个非常特别的问题:
    让我们比较一下 goto throw 声明。
    在我看来,这两者都做同样的事情:避免基于某种条件执行代码的某些部分。
    如果是这样的话 和Goto有相同的缺点?(如果有的话)?
    如果不是,那么区别就在于什么。

    任何有足够经验的人,谁能告诉 基本的 ,以下两个代码段的代码结构之间的概念差异?
    关于这些代码片段,不是“理论上”或“一般上”或“这里是一个不错的XKCD漫画!”.
    为什么第一个被认为是聪明的,后一个被认为是最致命的罪恶?

    #$a=1;
    #$b=2;
    
    /* SNIPPET #1 */
    
    try {
        if (!isset($a)) {
          throw new Exception('$a is not set');
        }
        if (!isset($b)) {
          throw new Exception('$b is not set');
        }
        echo '$a + $b = '.($a + $b)."<br>\n";
    } catch (Exception $e) {
        echo 'Caught exception: ', $e->getMessage(), "<br>\n";
    }
    
    /* SNIPPET #2 */
    
    if (!isset($a)) { 
      $message = '$a is not set';
      goto end;
    }
    if (!isset($b)) {
      $message = '$b is not set';
      goto end;
    }
    echo '$a + $b = '.($a + $b)."<br>\n";
    
    end:
    if (!empty($message)) {
      echo 'Caught exception: ', $message, "<br>\n";
    }
    

    注意,我知道投掷更有力和更灵活 做意大利面 . 这对我来说没有什么主要的区别。这是使用问题,而不是概念问题。

    编辑
    许多人告诉我,第一个例子应该是新的。
    原因:异常应仅用于处理错误,而不用于实现业务逻辑。
    看起来很明智。

    因此,停止无用代码执行的唯一方法就是goto(更不用说一些替代方法,例如while、return等,这是相同的问题,但很难实现)?

    11 回复  |  直到 13 年前
        1
  •  2
  •   Herbert    13 年前

    既然还没有人回答这一问题,OP认为可以接受,我就把我的帽子扔到戒指里去。

    …代码结构之间的基本概念差异 以下两个代码片段?

    没有 概念的 您所提供的两个代码片段之间的差异。在这两种情况下,都会测试一个条件,如果满足,则会将一条消息抛出到程序的另一部分以进行处理。

    为什么第一个被认为是辉煌的,后一个被认为是辉煌的 是最致命的罪?

    谢谢你,子母弹为下面的咆哮打开了大门。

    <RANT & GT;

    每个 编程构造具有滥用的可能性。教条式的迫害 goto 让我想起了对PHP的类似抨击。 PHP导致错误的编程实践。 相比: Goto引出了意大利面代码。

    简单地说: 古托 是“邪恶的”,因为埃德斯格·迪jkstra这么说,而尼克劳斯·沃思给了它一个认可的印章。-P

    </rand & gt;

    为了您的阅读乐趣: http://en.wikipedia.org/wiki/Goto

    可能对哥特人最著名的批评是艾德斯格1968年的一封信。 Dijkstra叫 转到被认为有害的语句 . 在那封信里 Dijkstra认为应该废除无限制的goto声明 因为高级语言使 分析和验证程序的正确性(尤其是 那些涉及循环的)。另一种观点出现在 Donald Knuth的Go-to语句结构化编程 分析许多常见的编程任务,发现在其中一些任务中 goto是要使用的最佳语言结构。

    接着说,

    一些程序员,如Linux内核设计器和编码器Linus Torvalds或软件工程师兼书籍作者Steve McConnell 反对Dijkstra的观点,指出Gotos可能是一个有用的 语言特性,提高程序速度、大小和代码清晰性, 但只有在以一种合理的方式使用时 程序员。

    也就是说,自从准将BASIC以来,我个人还没有找到goto的实际用途,但这既不是这里也不是那里。-)

        2
  •  13
  •   ssegvic    14 年前

    throw/catch比goto灵活得多:您可以从调用引发异常的代码的函数中进行捕获。此外,所需的析构函数被自动调用。

        3
  •  7
  •   Dean Harding    14 年前

    我想你应该换个角度问这个问题:你为什么要用 goto 什么时候例外情况完全适合这种情况?这就是例外 对于 .

    你也可以问“为什么要用 while , for 当我可以很容易地使用 古托

        4
  •  5
  •   ChrisF    14 年前

    在您的示例中,当您检查错误条件并引发异常或调用时,实际上没有区别。 goto 如果条件失败。您的示例可以重新编码以消除 任何一个 构建。

    其中例外 如果调用的方法可能有错误状态,但无法自行处理,则很有用,如以下伪代码所示:

    try
    {
        $c = add($a, $b);
        echo '$a + $b = '.($c)."<br>\n";
    }
    catch (Exception $e)
    {
        echo 'Caught exception: ', $e->getMessage(), "<br>\n";
    }
    

    这个 add 方法执行错误检查:

    if (!isset($a))
    {
        throw new Exception('$a is not set');
    }
    if (!isset($b))
    {
        throw new Exception('$b is not set');
    }
    

    然后返回加法的结果。

    这意味着您的主代码流显示了通过程序的预期路径。

        5
  •  4
  •   ircmaxell    14 年前

    goto 将执行路径硬编码到代码中。另一方面,异常允许在运行时确定执行路径。

    例如,假设有一个数据库类在出错时引发异常。除了例外,您可以捕获该错误,并在呈现错误页之前执行其他操作(例如清理分配的资源,或者如果使用非事务性DB类型,则可以“回滚”先前的更改)。如果使用goto,就没有机会这样做,因为goto会呈现错误页面。

    记住,保持代码的可重用性和灵活性。 古托 是两者的对立面…

        6
  •  3
  •   Petah    13 年前

    goto 我们做这样的事情是不是很忙:

    foreach ($items as $item) {
        if ($item->is_match()) goto match;
    }
    
    $item = new Item();
    
    match:
    render('find_item.php', $item);
    

    根据本协议:

    $matching_item = null;
    foreach ($items as $item) {
        if ($item->is_match()) {
            $matching_item = $item;
            break;
        }
    }
    if ($matching_item === null) {
        $item = new Item();
    }
    
    render('find_item.php', $item);
    
        7
  •  2
  •   Jon B    14 年前

    实际上,您的两个代码段之间的区别在于,您必须花更多的时间用“goto”代码向其他程序员解释自己。

    无论好坏,大多数程序员都认为您应该 从未 使用GOTO。也许您可以证明这是没有根据的,并且您的goto代码是实现该函数的最佳方法。即便如此,你还是要和同事或任何与你合作的人打交道,让他们接受。

    如果你是一个人工作,没有人会看到你的代码-使用你喜欢的任何东西。但是,如果你是在一个团队中工作,有时阻力最小的路径是最谨慎的。

        8
  •  2
  •   Jeremy Powell    14 年前

    “错”的是 goto 它可以实现多种控制机制,而不仅仅是 throw 因此,几乎没有固有的结构。因此,有几个原因可以解释为什么脚本程序员会有兴趣使用 古托 选择:

    首先,我们开始看到脚本从纯解释代码移动到编译的字节代码。很好的例子可以在任何地方找到,比如python、perl 6、scala(lift)、clojure(compojure)。甚至PHP也有字节代码编译器。自从 古托 由于结构很少,控制机制的编译是不可能发生的,这是一个相当大的性能损失,因为现代编译器通常都非常擅长这一点。为了 编译器可以开始假设一个异常被抛出是不常见的,因此它通常会以一个不太理想的“异常”控制路径为代价来优化“正常”控制路径。

    即使您没有一个完整的编译器,当程序员使用具有更多结构的控制机制时,解释器也可以大大帮助程序员。例如, for 循环块的词法范围是由编译器/解释器确定的,因此程序员可以使用这个范围来模块化代码块。否则,与 古托 您必须污染变量命名空间。

    此外,如果您的语言允许您声明 异常,编译器/解释器可以通知您,您没有处理您调用的方法可能遇到的所有可能的异常(类似于 throws Java,如果你在那里有经验的话。用 古托 编译器不知道您要做什么,所以在编译和测试期间它不会帮助您。

    goto还要求程序员从错误中恢复。想象一下,如果您有这样的代码(从片段中抓取并编辑):

    if (!isset($a)) { 
      $message = '$a is not set';
      goto errorA;
    }
    if (!isset($b)) {
      $message = '$b is not set';
      goto errorB;
    }
    if (!moonInRightPhase) {
       goto errorP
    }
    echo '$a + $b = '.($a + $b)."<br>\n";
    
    errorA:
    // Do something non-trivial and unique to handle $a not being set.
    goto afterError
    
    errorP:
    // Do something non-trivial and unique to handle moon phase
    // This error requires drastic failure of code path:
    goto failure
    
    errorB:
    // Do something non-trivial and unique to handle $b not being set.
    goto afterError
    
    afterError:
    // Program continues
    
    return SUCCESS
    
    failure:
    return FAILURE
    

    这里的问题是程序员必须做正确的事情。如果他忘了 goto afterError ,他将运行下一个异常路径。用 这些机制不太容易出错。

    最后,我的个人经历让我不喜欢 古托 陈述只是因为它不容易阅读。当我试图理解一段带有四五个标签的代码时 some-error , fail , retry 它们不靠近违规/例外代码,解开它们可能是一场噩梦。如果不容易阅读,那么即使是程序员试图回顾他或她一年前所做的事情,也可能导致错误。

    作为这个答案的后记,我不认为“错误”是正确的描述方式 古托 . 这可能来自于对著名的狄克斯特拉报纸的耸人听闻。”“强大”可能是一个更好的术语,因为它意味着它可以做几乎所有的事情,但即使是最简单的错误也会使“错误”变成“可怕的错误”。我们不应该禁止使用工具,因为它们非常危险;我们应该更好地教育人们了解它们的危险,让他们自己决定。

        9
  •  1
  •   Michael Spector    14 年前

    goto 与throw相比,它可能有一点性能提升,因为它不会创建任何异常堆栈。

        10
  •  0
  •   Matteo Riva    14 年前

    我不像很多人那样讨厌goto,但我认为它的主要问题是它不局限于特定的“范围”。对于每个其他的控制结构,您知道它从哪里开始,从哪里结束。另一方面,goto标签可能被放置在更不可预测的地方。当然,您可以搜索标签,但它会破坏可读性。

    当然,一切都取决于它是如何使用的。

        11
  •  -3
  •   Robert Deml    14 年前

    也不要使用。在大部分代码周围使用“while(1)”和“break”语句,以便跳到末尾。

    while(1)
    {
        if (!isset($a)) { 
          $message = '$a is not set';
          break;
        }
        if (!isset($b)) {
          $message = '$b is not set';
          break;
        }
    
        echo '$a + $b = '.($a + $b)."<br>\n";
        break;
    }
    
    if (!empty($message)) {
      echo 'Caught exception: ', $message, "<br>\n";
    }