代码之家  ›  专栏  ›  技术社区  ›  dawg

我应该使用Perl的条件语句吗?:运算符作为switch/case语句还是代替if elsif?

  •  17
  • dawg  · 技术社区  · 15 年前

    conditional C's conditional operator .

    (test) ? (if test was true) : (if test was false)
    

    如果与左值一起使用,则可以通过一个操作分配和测试:

    my $x=  $n==0 ? "n is 0" : "n is not 0";
    

    我在读伊戈尔·奥斯特罗夫斯基的博客 A neat way to express multi-clause if statements in C-based languages

    例如:(编辑:使用Jonathan Leffler更可读的形式…)

    # ternary conditional form of if / elsif construct:
    my $s=
          $n == 0     ? "$n ain't squawt"
        : $n == 1     ? "$n is not a lot"
        : $n < 100    ? "$n is more than 1..."
        : $n < 1000   ? "$n is in triple digits"
        :               "Wow! $n is thousands!" ;  #default
    

    读起来比用Perl写的要容易得多: my $t=do{ if };

    # Perl form, not using Switch or given / when
    my $t = do {
        if    ($n == 0)   { "$n ain't squawt"        }
        elsif ($n == 1)   { "$n is not a lot"        }
        elsif ($n < 100)  { "$n is more than 1..."   }
        elsif ($n < 1000) { "$n is in triple digits" }
        else              {  "Wow! $n is thousands!" }
    };
    

    这里有什么问题或缺点吗?为什么我不这样写一个扩展的条件形式而不是使用 if(something) { this } elsif(something) { that }

    条件运算符有 right associativity and low precedence . 所以:

    a ? b : c ? d : e ? f : g
    

    解释为:

    a ? b : (c ? d : (e ? f : g))
    

    ?: . 我想你也可以用大括号把方块拼起来。

    use Switch 或者关于Perl5.10 given/when 构造,我不想寻找使用这些的建议。

    • 您见过Perl中使用的这种语法吗?**我没有,它也不在 perlop perlsyn 作为交换的替代品。

    • 以这种方式使用条件/三元运算符是否存在潜在的语法问题或“gotchas”?

    --------编辑--

    我接受了乔纳森·莱夫勒的回答,因为他指给我看 Perl Best Practices 表三角形。

    my $salute;
    if ($name eq $EMPTY_STR) {
        $salute = 'Dear Customer';
    }
    elsif ($name =~ m/\A ((?:Sir|Dame) \s+ \S+)/xms) {
        $salute = "Dear $1";
    }
    
    elsif ($name =~ m/([^\n]*), \s+ Ph[.]?D \z/xms) {
        $sa1ute = "Dear Dr $1";
    }
    else {
        $salute = "Dear $name";
    }
    

    对:

               # Name format...                            # Salutation...
    my $salute = $name eq $EMPTY_STR                       ? 'Dear Customer'
               : $name =~ m/ \A((?:Sir|Dame) \s+ \S+) /xms ? "Dear $1"
               : $name =~ m/ (.*), \s+ Ph[.]?D \z     /xms ? "Dear Dr $1"
               :                                             "Dear $name"
               ;
    

    我的结论是:

    • 康威的 ?: if/elsif

    • 如果您有Perl5.13.1,请使用 my $t=do { given { when } }; 作为一项任务 rafi has done. 现在是最好的习惯用法,除非表格三元格式更适合您的特定情况。

    • 如果您有Perl5.10+使用 给定/时间 Switch 或者如果你需要一种外壳类型的开关。

    • 简单的 替代方案或作为案例陈述的替代方案。总比用 我想。

    4 回复  |  直到 9 年前
        1
  •  15
  •   Jonathan Leffler    15 年前

    为条件运算符显示的布局很难读取。 Perl Best Practices 推荐:

    my $s = $n == 0   ? "$n ain't squawt"
          : $n == 1   ? "$n is not a lot"
          : $n < 100  ? "$n is more than 1..."
          : $n < 1000 ? "$n is in triple digits"
          :             "Wow! $n is thousands!";  # default...
    

    if 符号也是:

      if    ($n == 0)   { $t = "$n ain't squawt";        }
      elsif ($n == 1)   { $t = "$n is not a lot";        }
      elsif ($n < 100)  { $t = "$n is more than 1...";   }
      elsif ($n < 1000) { $t = "$n is in triple digits"; }
      else              { $t = "Wow! $n is thousands!" ; }  
    

    这两种格式都强调代码各部分的相似性,使其更易于阅读和理解。

        2
  •  19
  •   rafl    15 年前

    我见过perl中使用的这个习惯用法。作为三元运算符 ? : 是的,嗯。。接线员,记录在 perlop ,不是 perlsyn

    在我看来,这是一种习惯性的Perl,但是Perl的主要目的似乎是避免缺少适当的 switch if/else -瀑布。然而,多年前在Perl5.10.0中已经修复了这个问题。这些天来,我看不出有多少理由不这样写,这似乎比(ab)使用三元组可读性强得多:

    given ($n) {
        when (0)         { $t = "$_ ain't squawt"        }
        when (1)         { $t = "$_ is not a lot"        }
        when ($_ < 100)  { $t = "$_ is more than 1..."   }
        when ($_ < 1000) { $t = "$_ is in triple digits" }
        default          { $t = "Wow! $_ is thousands!"  }
    }
    

    或者,从perl 5.13.1开始,即使是:

    my $t = do {
        given ($n) {
            when (0)         { "$_ ain't squawt"        }
            when (1)         { "$_ is not a lot"        }
            when ($_ < 100)  { "$_ is more than 1..."   }
            when ($_ < 1000) { "$_ is in triple digits" }
            default          {  "Wow! $_ is thousands!" }
        }
    };
    

    my @cases = (
        [sub { $_ == 0 },   sub { "$_ ain't squawt"        }],
        [sub { $_ == 1 },   sub { "$_ is not a lot"        }],
        [sub { $_ < 100 },  sub { "$_ is more than 1..."   }],
        [sub { $_ < 1000 }, sub { "$_ is in triple digits" }],
        [sub { 1 },         sub { "Wow! $_ is thousands!"  }],
    );
    
    for my $case (@cases) {
        local $_ = $n;
        next unless $case->[0]->();
        $t = $case->[1]->();
        last;
    }
    

    而这避免了使用巨大的 if/elsif/else -层叠,而且不需要最近perls的特性,对于这个简单的例子来说,这可能不值得花费精力。然而,我可以看到这样一种方法在很多条件下都很有用,并且有支持旧perl的限制。

    来自cjm的注释 :您也可以在Perl 5的所有版本中执行此操作:

    my $t = do {
        if    ($n == 0)   { "$n ain't squawt"        }
        elsif ($n == 1)   { "$n is not a lot"        }
        elsif ($n < 100)  { "$n is more than 1..."   }
        elsif ($n < 1000) { "$n is in triple digits" }
        else              {  "Wow! $n is thousands!" }
    };
    
        3
  •  5
  •   brian d foy    15 年前

    我见过很多链式条件句,有时用,有时讨厌。它很方便,但很难看,除非你走极端去格式化和简化填空表达式。

    一旦你遇到他们几次,意识到这是个成语,他们就不难理解了。不过,更容易理解正确的switch语句。也不太可能把冒号放错位置,把一切都搞得一团糟。

        4
  •  4
  •   draegtun    15 年前

    还有另一条路!

    my $t = sub {
        return "$n ain't squawt"        if $n == 0;
        return "$n is not a lot"        if $n == 1;
        return "$n is more than 1..."   if $n < 100;
        return "$n is in triple digits" if $n < 1000;
        return "Wow! $n is thousands!";
    }->();
    

    我在几篇博文中提到了这一点: