perl - 我应该使用 Perl 的条件吗? : operator as a switch/case statement or instead of if elsif?

标签 perl syntax conditional-statements

Perl 有一个 conditionalC'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";

我正在阅读 Igor Ostrovsky 的博客 A neat way to express multi-clause if statements in C-based languages并意识到这在 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))

如果您的测试使用了优先级低于 ?: 的少数运算符之一,我想您可能需要括号。 。我认为您也可以将 block 放入带大括号的形式中。

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

这些是我的问题:

  • 你见过 Perl 中使用的这种语法吗?** 我没有见过,而且 perlop 中也没有它。或perlsyn作为切换的替代方案。

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

  • 意见:对您来说更易读/理解吗?它与 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"
           ;

我的结论是:

  • 康威的 ?:对我来说,示例比 if/elsif 更具可读性和更简单形式,但我可以看到该形式如何变得难以理解。

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

  • 如果您有 Perl 5.10+,请使用 given/when一般来说,而不是 Switch或者如果您需要某种外壳类型的开关。

  • 对于较早的 Perl 来说,这是一种很好的简单替代形式或作为 case 语句的替代形式。它比使用 Switch 更好我认为。

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

最佳答案

我在 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!" }
};

关于perl - 我应该使用 Perl 的条件吗? : operator as a switch/case statement or instead of if elsif?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3898836/

相关文章:

java - 为什么java中有的关键字以大写字母开头,有的以小写字母开头?

java - 生产者消费者修改

perl - 为什么 File::Find 不处理我损坏的符号链接(symbolic link)?

regex - 在一个文件中查找具有相同列对的行

syntax - 我可以让 "&&"或 "-and"在 PowerShell 中工作吗?

python - "from gremlin_python.process.graph_traversal import __"在 Python 中起什么作用?

perl - 如何将 Devel::Cover 与证明一起使用?

perl - Catalyst:将查询参数传递给 "forward"调用

php - 在 php 中使用 @ 而不是 isset

if-statement - 在 Haxe 的 if 语句中使用对象的存在