【问题标题】:Why use short-circuit code?为什么要使用短路代码?
【发布时间】:2010-12-17 05:00:31
【问题描述】:

相关问题Benefits of using short-circuit evaluationWhy would a language NOT use Short-circuit evaluation?Can someone explain this line of code please? (Logic & Assignment operators)

对于使用短路代码的语言的好处存在疑问,但我想知道对程序员有什么好处?只是它可以让代码更简洁一点吗?还是有性能原因?

我不是在询问需要评估两个实体的情况,例如:

if($user->auth() AND $model->valid()){
  $model->save();
}

对我来说,其中的推理很清楚 - 因为两者都需要为真,如果用户无法保存数据,您可以跳过成本更高的模型验证。

这也有一个(对我来说)明显的目的:

if(is_string($userid) AND strlen($userid) > 10){
  //do something
};

因为使用非字符串值调用strlen() 是不明智的。

我想知道的是在不影响任何其他语句的情况下使用短路代码。例如,来自 Zend Application 默认索引页面:

defined('APPLICATION_PATH')
 || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

这可能是:

if(!defined('APPLICATION_PATH')){
  define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
}

或者甚至作为一个单一的陈述:

if(!defined('APPLICATION_PATH'))
  define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

那么为什么要使用短路代码呢?只是为了使用逻辑运算符代替控制结构的“酷”因素?合并嵌套的 if 语句?因为它更快?

【问题讨论】:

  • 关于速度的一点说明:如果你有一个中规中矩的编译器,它将为 if 语句和短路生成相同的机器代码。如果你不这样做,它会产生足够糟糕的代码,以至于一些源级微优化的几个额外周期将在噪音中丢失。很简单,这并不重要。
  • @David 对于脚本语言也是这样吗?
  • @TimLytle 在解释语言中,由于要进行不同的解析和解释,您可能会有不同的行为。在代码有机会运行之前,编译器可以从中受益。
  • 控制结构给人的印象是正在采取一些行动。短路给人的印象是正在评估表达式。我觉得短路经常被用来帮助开发人员知道除了评估最终值(没有副作用等)之外没有任何事情发生。

标签: coding-style short-circuiting code-structure


【解决方案1】:

这样想,如果你有这样的陈述

if( A AND B )

如果 A 返回 FALSE,您可能只想在极少数特殊情况下评估 B。由于这个原因,不使用短路评估是令人困惑的。

短路评估还通过防止另一个括号缩进使您的代码更具可读性,并且括号有加起来的趋势。

【讨论】:

    【解决方案2】:

    短路运算符在尚未提及的两种重要情况下很有用:

    案例 1。假设您有一个指针,它可能是也可能不是NULL,并且您想检查它不是NULL,并且它指向的东西不是0。但是,如果指针为 NULL,您必须不要取消引用该指针。如果没有短路运算符,您将不得不这样做:

    if (a != NULL) {
      if (*a != 0) {
        ⋮
      }
    }
    

    但是,短路运算符允许您更紧凑地编写此代码:

    if (a != NULL && *a != 0) {
      ⋮
    }
    

    如果aNULL,则不会评估*a

    案例 2。如果您想将变量设置为从一系列函数之一返回的非假值,您可以简单地执行以下操作:

    my $file = $user_filename ||
               find_file_in_user_path() ||
               find_file_in_system_path() ||
               $default_filename;
    

    这会将$file 的值设置为$user_filename(如果存在),或者设置find_file_in_user_path() 的结果(如果为真),或者......等等。这在 Perl 中可能比在 C 中更常见,但我在 C 中看到过。

    还有其他用途,包括您上面引用的相当人为的示例。但它们是一种有用的工具,我在用不太复杂的语言编程时错过了它。

    【讨论】:

    • 那是“合并嵌套的 if 语句”,我不记得以前看过或想出示例代码。
    【解决方案3】:

    事实实际上是性能。编译器中使用短路来消除死代码,从而节省文件大小和执行速度。在运行时,如果结果不影响答案,则短路不会执行逻辑表达式中的剩余子句,从而加快了公式的评估。我正在努力记住一个例子。例如

    a 和 b 和 c

    这个公式中有两个项从左到右计算。

    如果 a AND b 的计算结果为 FALSE,那么下一个表达式 AND c 可以是 FALSE AND TRUE 或 FALSE AND FALSE。无论 c 的值是多少,两者都评估为 FALSE。因此编译器在编译格式中不包含 AND c 从而使代码短路。

    为了回答这个问题,存在一些特殊情况,即编译器无法确定逻辑表达式是否具有恒定输出,因此不会使代码短路。

    【讨论】:

      【解决方案4】:

      与 Dan 所说的有关,我认为这完全取决于每种编程语言的约定。我看不出有什么区别,所以在每种编程语言中做任何惯用的事情。可能会想到的一件事是,如果您必须进行一系列检查,在这种情况下,短路样式将比替代 if 样式更清晰。

      【讨论】:

        【解决方案5】:

        对于程序员来说,相对于另一种更冗长的语法而言,不太冗长的语法的好处是:

        • 输入更少,因此编码效率更高
        • 阅读量更少,因此可维护性更好。

        现在我只讨论不太冗长的语法在任何方面都不棘手或不聪明的情况,只是同样公认的做法,但字符更少。

        通常当您看到一种语言的特定结构时,您希望您使用的语言可以具有,但以前甚至没有意识到这一点。我脑海中的一些例子:

        • Java 中的匿名内部类,而不是将指针传递给函数(代码行数更多)。
        • 在 Ruby 中,||= 运算符用于计算表达式并在其计算结果为 false 或为 null 时分配给它。当然,您可以通过 3 行代码实现相同的目标,但为什么呢?
        • 还有更多...

        【讨论】:

          【解决方案6】:

          我认为您的示例是针对凉爽因素的。没有理由编写这样的代码。

          编辑:出于惯用原因,我这样做没有问题。如果使用一种语言的其他人都使用短路评估来制作每个人都能理解的类似语句的实体,那么您也应该这样做。然而,我的经验是,这种代码很少用 C 系列语言编写。正确的形式是正常使用“if”语句,它将条件(可能没有副作用)与条件控制的函数调用(可能有很多副作用)分开。

          【讨论】:

            【解决方案7】:

            我不了解 PHP,而且我从未见过在 C 语言家族的 if 或 while 条件之外使用短路,但在 Perl 中这样说是非常惯用的:

            open my $filehandle, '<', 'filename' or die "Couldn't open file: $!";
            

            在一个语句中包含所有内容的一个优点是变量声明。否则你不得不说:

            my $filehandle;
            unless (open $filehandle, '<', 'filename') {
                die "Couldn't open file: $!";
            }
            

            在这种情况下,很难说第二个更干净。如果使用没有unless的语言,它会更加冗长

            【讨论】:

            • 更少的输入让程序员开心。
            【解决方案8】:

            用它来迷惑人!

            【讨论】:

            • 或者也许是为了防止(容易混淆的)riff-raff 弄乱代码。
            【解决方案9】:

            如果您有一个昂贵的调用(性能方面)函数,它在右侧返回一个布尔值,而您只希望在另一个条件为真(或假)时才调用它?在这种情况下,短路可以为您节省许多 CPU 周期。由于嵌套的 if 语句更少,它确实使代码更简洁。因此,出于您在问题末尾列出的所有原因。

            【讨论】:

            • 是的,这是我举的例子之一,原因很明显。请参阅 $model->valid() 示例。
            • 没错。您引用的所有理由都是使用短路评估的很好理由。
            猜你喜欢
            • 1970-01-01
            • 2015-09-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-03
            • 2010-10-25
            • 1970-01-01
            • 2012-12-28
            相关资源
            最近更新 更多