【问题标题】:Ternary operator doesn't allow iterative operator in it, but if-else does?三元运算符不允许在其中使用迭代运算符,但 if-else 允许吗?
【发布时间】:2017-02-14 09:26:58
【问题描述】:

我注意到,如果我用三元运算符替换我正在使用的 if-else 语句,我在尝试运行我的代码时会遇到编译错误。我相信罪魁祸首是我在if-else 中的foreach() 循环。你知道为什么在这种情况下三元运算符的行为与 if-else 构造不同吗?

我的代码是这样的

#!/program/perl_v5.6.1/bin/perl5.6.1

use strict;
use warnings;


my $fruits_array_ref = &get_fruits();
if($fruits_array_ref != 0) {
    print("$_ is a fruit.\n") foreach(@$fruits_array_ref);
}
else {
    print("Maybe you like vegetables?\n");
}


sub get_fruits() {
    my @fruit_list;
    my $shopping_list = "/home/lr625/grocery_items";

    open(my $shopping_list_h, "<", $shopping_list) or die("Couldn't open.\n");
    while(my $line = <$shopping_list_h>) {
        next if $line =~ /^\#/;
        chomp($line);
        push(@fruit_list, $line);
    }
    close($shopping_list_h) or die("Couldn't close.\n");

    scalar(@fruit_list) > 0 ? return(\@fruit_list) : return(0);
}

我在购物清单中的数据看起来像

# this is a header
# to my grocery list
apple
banana
grape
orange

我将 if-else 替换为 ?: 运算符,现在在 main 函数中看起来像这样。

my $fruits_array_ref = &get_fruits();
$fruits_array_ref != 0 ? print("$_ is a fruit.\n") foreach(@$fruits_array_ref) : print("Maybe you like vegetables?\n");

另外,作为参考,我的错误说。

test.pl 第 8 行,“) foreach”附近的语法错误

test.pl 的执行由于编译错误而中止。

【问题讨论】:

  • 这与您的问题无关,但如果您确实使用 Perl 5.6.1,您应该更新到新版本,例如 5.18 或 5.22 或您的操作系统提供的任何版本。 5.6 真的,真的老了。但是,我用 5.22.1 尝试了您的代码并得到了相同的结果。
  • 我愿意,但我坚持做任何能给我的工作。必须用我得到的东西来凑合。 @choroba 很好地解释了我正在尝试将控制结构作为三元运算符中的操作数,所以我可能会尝试使用 do,或者我会坚持使用 if-else 的可预测行为
  • 您可能需要花时间来吸收 Inferno 在他的回答中所说的话。您似乎有接近“聪明”解决方案的危险,而且,维护明智,“聪明”很少是一种美德。
  • 是的,我做到了,并且我注意到我在我的子功能中一直在研究一个“聪明”的解决方案,我认为最后。使用我的新知识,我认为最好写成... return( scalar(@fruit_list) &gt; 0 ? \@fruit_list : 0 );

标签: perl foreach ternary-operator


【解决方案1】:

if-else是一个流控制结构,?-:是一个以表达式为操作数的运算符。 foreach 是流控结构,不是表达式。

您可以使用do 将任何代码块转换为表达式:

$fruits_array_ref != 0
    ? do { print "$_ is a fruit.\n" for @$fruits_array_ref }
    : print "Maybe you like vegetables?\n";

但是为什么呢?

【讨论】:

    【解决方案2】:

    三元运算符在?: 之前采用参数,请参阅in perlop。它可以评估表达式并将其结果用于此目的。但是循环不是表达式,不能在里面“运行”。

    为了演示——如果你坚持的话,你可以调用一个函数作为副作用打印

    sub greet { say "hello" for 1..3 }
    
    my $x = 1;
    ($x == 1) ? greet() : say "bye";
    

    实际上在生产代码中执行此操作是另一回事,并且可能不是一个好主意。重点是完全依赖副作用,这与我们通常想做的相反。


    解释我上面的评论——三元运算符的要点是返回一个值,在一个语句中选择两个值。虽然它与 if-else “等效”,但它的使用(理想情况下)意味着非常不同。因此,无论如何,在?: 参数中进行一些其他处理实际上是对符号的滥用,是一种副作用,因为它们旨在产生要返回的值。打印出来与产生和返回值的想法相反。这不是批评,操作符​​经常被许多人用作语法快捷方式。

    从这个意义上说,我建议恢复为 if-else 来执行显示的操作。

    【讨论】:

      【解决方案3】:

      foreach 语句修饰符只能用在语句的末尾。

      你为什么使用?:?如果您想要一个结果,通常只会这样做。

      您可以将print...foreach... 包装在do {...} 中,或者您可以使用map 而不是foreach。或者将其保留为 if/else。

      【讨论】:

        【解决方案4】:

        其他答案已经指出,您不能按照您尝试的方式使用三元运算符。为了完整起见并为您提供一些合理的用例,请查看以下示例:

        #1:用作子程序参数

        testSub($var eq 'test' ? 'foo' : 'bar');
        

        在这里,您可以看到如果$var 等于字符串test,则使用参数foo 调用子例程testSub。否则testSub 将被调用bar。这很有用,因为您不能使用 if-else 结构作为子参数。

        #2:用于条件赋值

        my $result = $var eq 'test' ? 'foo' : 'bar'; # $result will contain 'foo' or 'bar'
        

        三元运算符并不是简单地替换if-else 结构。因为它返回一个值(这里是foobar),所以使用这个值也是有意义的。如果您不打算使用返回值,则应使用通常的if-else

        【讨论】:

          猜你喜欢
          • 2020-07-06
          • 2011-12-27
          • 2015-04-25
          • 1970-01-01
          • 2010-12-12
          • 2021-01-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多