我应该使用Perl的条件吗? :operator是一个switch / case语句,还是代替elsif?

时间:2010-10-10 02:59:23

标签: perl syntax conditional

Perl的conditional运算符与C's conditional operator相同。

要刷新,C和Perl中的条件运算符是:

(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阅读Igor Ostrovsky的博客,并意识到这在Perl中确实是一种“整洁的方式”。

例如:(编辑:使用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中写的更容易: (编辑:在rafi的回答中使用了cjm更优雅的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或关于Perl 5.10的given/when构造,我并不是在寻找使用它们的建议。

这是我的问题:

  • 您是否看到过Perl中使用的这种语法?**我没有,而且它不在perlopperlsyn作为切换的替代方法。

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

  • 意见:你的可读性/可理解性更强吗?它与Idiomatic Perl一致吗?

--------编辑 -

我接受了Jonathan Leffler的回答,因为他指出我Perl Best Practices表格三元组的相关部分是6.17。这使我可以进一步调查使用情况。 (如果您使用Google Perl Tabular Ternaries,则可以看到其他评论。)

康威的两个例子是:

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";
}

VS

           # 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"
           ;

我的结论是:

  • Conway的?:示例比if/elsif表单更易读,更简单,但我可以看到表单难以理解。

  • 如果你有Perl 5.13.1,请使用my $t=do { given { when } };作为rafi has done.的作业我认为given/when现在是最好的习惯用法,除非表格三元格式更适合你的具体情况。

  • 如果Perl 5.10+一般使用given/when而不是Switch,或者需要某种案例类型切换。

  • 较旧的Perl,这是简单备选方案的良好形式,或作为案例陈述的替代。这比使用Switch更好。

  • 从右到左的关联性意味着从下到上评估表单。请记住,使用时......

4 个答案:

答案 0 :(得分:19)

我在perl中看到过这个习惯用法。由于三元运算符? :是一个运算符,它在perlop中记录,而不是perlsyn

在我看来,它是一种惯用的Perl,但Perl的主要目的似乎是避免缺少正确的switch语句,而不是写出巨大的if/else - 级联。但是,这在几年前已经在perl 5.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!" }
    }
};

另一种选择是这样的,它适用于所有perl版本:

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的功能,但这个简单的例子可能不值得努力。但是,我可以非常看到这样的方法在很多条件下都有用,并且需要支持旧的perls。

(另请注意,您的初始示例不会处理$ n小于零或根本不是数字。)

来自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!" }
};

答案 1 :(得分: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 :(得分:5)

我已经看过相当多的链条条件,有时会用它,并且总是讨厌它。这很方便但很难看,除非你走极端去格式化它并简化插页式广告。

一旦你遇到它们并且意识到这是一个成语,它们就不那么难以理解了。但是,更容易理解正确的switch语句。也有可能错误地放置冒号并以难以点的方式弄乱一切。

答案 3 :(得分:4)

还有另一种方式!

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!";
}->();

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

/ I3az /