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

daw*_*awg 17 syntax perl conditional

Perl有一个条件运算符,它与C的条件运算符相同.

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

(test) ? (if test was true) : (if test was false)
Run Code Online (Sandbox Code Playgroud)

如果与左值一起使用,您可以使用一个动作进行分配和测试:

my $x=  $n==0 ? "n is 0" : "n is not 0";
Run Code Online (Sandbox Code Playgroud)

我正在阅读伊戈尔·奥斯特罗夫斯基(Igor Ostrovsky)的博客,以一种简洁的方式来表达基于C语言的多语句if语句,并且意识到这在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
Run Code Online (Sandbox Code Playgroud)

其中读取的内容比许多人在Perl中写的更容易:(编辑:my $t=do{ if };在rafi的回答中使用了cjm更优雅的形式)

# 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!" }
};
Run Code Online (Sandbox Code Playgroud)

这里有任何问题或缺点吗?为什么我不以这种方式编写扩展条件形式而不是使用if(something) { this } elsif(something) { that }

条件运算符具有正确的关联性和低优先级.所以:

a ? b : c ? d : e ? f : g
Run Code Online (Sandbox Code Playgroud)

被解释为:

a ? b : (c ? d : (e ? f : g))
Run Code Online (Sandbox Code Playgroud)

如果您的测试使用的是少数优先级较低的运算符之一,我想您可能需要括号?:.你也可以把格子放在带支撑的形状中.

我确实知道被弃用的use Switch或关于Perl 5.10的given/when结构,我不是在寻找使用它们的建议.

这些是我的问题:

  • 你有没有看到Perl中使用的这种语法?**我没有,它不在perlopperlsyn作为切换的替代.

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

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

--------编辑 -

我接受了Jonathan Leffler的回答,因为他向我指出了Perl最佳实践.关于表格三元的相关部分是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";
}
Run Code Online (Sandbox Code Playgroud)

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"
           ;
Run Code Online (Sandbox Code Playgroud)

我的结论是:

  • ?:对于我而言,Conway的示例比if/elsif表单更具可读性和简单性,但我可以看到表单如何难以理解.

  • 如果您有Perl 5.13.1,请将my $t=do { given { when } };其用作rafi已完成的任务.我认为given/when现在是最好的成语,除非表格三元格式更适合您的特定情况.

  • 如果您通常使用Perl 5.10+ given/when而不是Switch或者如果您需要某种类型的案例类型切换.

  • 较旧的Perl,这是一个很好的形式,用于简单的替代或作为案例陈述的替代.它比Switch我想的更好.

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

raf*_*afl 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!"  }
}
Run Code Online (Sandbox Code Playgroud)

或者,从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!" }
    }
};
Run Code Online (Sandbox Code Playgroud)

另一个替代方案是这样的,适用于所有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;
}
Run Code Online (Sandbox Code Playgroud)

虽然这可以避免使用巨大的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!" }
};
Run Code Online (Sandbox Code Playgroud)


Jon*_*ler 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...
Run Code Online (Sandbox Code Playgroud)

有时候用符号表示更紧凑的符号也更好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!" ; }  
Run Code Online (Sandbox Code Playgroud)

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


bri*_*foy 5

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

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