Perl “错误地进入”;否则";条款

Perl “错误地进入”;否则";条款,perl,ternary-operator,Perl,Ternary Operator,我有以下代码: # List of tests my $tests = [("system_test_builtins_sin", "system_test_builtins_cos", "system_test_builtins_tan")]; # Provide overrides for certain variables that may be needed because of special cases # For example, cos must be executed 100

我有以下代码:

# List of tests
my $tests = [("system_test_builtins_sin", "system_test_builtins_cos", "system_test_builtins_tan")];

# Provide overrides for certain variables that may be needed because of special cases
# For example, cos must be executed 100 times and sin only 5 times.
my %testOverrides = (
    system_test_builtins_sin => {
        reps => 5,
    },
    system_test_builtins_cos => {
        reps => 100,
    },
);

my %testDefaults = (
    system_test_reps => 10,
);

# Execute a system tests
foreach my $testName (@$tests)
{
    print "Executing $testName\n";
    my $reps;

    if (exists $testOverrides{$testName}{reps})
        { $reps = $testOverrides{$testName}{reps}; }
    else
        { $reps = $testDefaults{system_test_reps}; }
    print "After long if: $reps\n";
    exists $testOverrides{$testName}{reps} ? $reps = $testOverrides{$testName}{reps} : $reps = $testDefaults{system_test_reps};
    print "After first ternary: $reps\n";
    exists $testOverrides{$testName}{reps} ? $reps = $testOverrides{$testName}{reps} : print "Override not found.\n";
    print "After second ternary: $reps\n";
}
这将提供以下输出:

Executing system_test_builtins_sin
After long if: 5
After first ternary: 10
After second ternary: 5
Executing system_test_builtins_cos
After long if: 100
After first ternary: 10
After second ternary: 100
Executing system_test_builtins_tan
After long if: 10
After first ternary: 10
Override not found.
After second ternary: 10

这个输出是最意想不到的!我不明白为什么第一个三元似乎总是执行“if false”子句。它总是赋值为10。我还尝试将“false”子句更改为
$reps=6
,我发现它总是得到6的值。为什么三元逻辑依赖于第三个(如果为false)子句的内容?

下面是一个简单的脚本,说明了这个问题:

#!/usr/bin/perl

use strict;
use warnings;

my $x;

1 ? $x = 1 : $x = 0;
print "Without parentheses, \$x = $x\n";

1 ? ($x = 1) : ($x = 0);
print "With parentheses, \$x = $x\n";
它产生以下输出:

Without parentheses, $x = 0
With parentheses, $x = 1
我不确定赋值和
?:
之间的关系是否可以用运算符优先级来完全解释。(例如,我相信C和C++在某些情况下的行为可能不同) 运行
perldoc-perlop
并搜索“条件运算符”,或查找;它涵盖了这个确切的问题(比我在这里做的更简洁)

无论如何,我认为使用
if
/
else
语句比使用
?:
运算符更清晰。或者,由于“true”和“false”分支都分配给同一个变量,因此更好地使用
?:
可以更改以下内容:

exists $testOverrides{$testName}{reps}
    ? $reps = $testOverrides{$testName}{reps}
    : $reps = $testDefaults{system_test_reps};
为此:

$reps = ( exists $testOverrides{$testName}{reps}
          ? testOverrides{$testName}{reps}
          : $testDefaults{system_test_reps} );
但是,我不得不换行以避免滚动,这一事实再次表明if/else更清晰

你也可以考虑使用<代码>//< /Cult>运算符,除非你被一个不支持它的Perl的旧版本所困扰。(它是由Perl5.10引入的。)它也被称为“defined or”操作符。这:

$x // $y
相当于

defined($x) ? $x : $y
所以你可以写:

$reps = $testOverrides{$testName}{reps} // $testDefaults{system_test_reps};

这并不具有完全相同的语义,因为它使用
defined
而不是
exists
来测试表达式;如果
$testOverrides{$testName}{reps}
存在,但其值为
undef

-p
-p
选项
B::Deparse
可用于解决以下问题:

$ perl -MO=Deparse,-p -e '$condition ? $x = $value1 : $x = $value2'
(($condition ? ($x = $value1) : $x) = $value2);

正如基思·汤普森(Keith Thompson)所指出的,这一切都与优先权有关。如果条件为false,则最终赋值为
$x=$value2
。如果条件为true,则赋值为
($x=$value1)=$value2
——无论哪种方式,结果都是将
$value2
赋值给
$x

,感谢您给我们的代码示例。现在我们可以把它撕成碎片了

不要使用三元运算符。这是一种最初让C程序员感到舒适的感染。在C语言中,使用三元运算符是因为它最初比if/else语句更有效。然而,编译器对于优化代码非常好,所以这不再是真的,现在在C和C++编程中是令人沮丧的。用C语言编程已经够难的了,因为它没有三元运算符

Perl编译器在优化代码方面也非常有效,因此您应该始终以最大的清晰度编写代码,这样,其他没有编程能力并且在维护代码方面遇到困难的人就可以混日子了

您遇到的问题是运算符优先级问题。你假设:

(exists $testOverrides{$testName}{reps}) 
    ? ($reps = $testOverrides{$testName}{reps}) 
    : ($reps = $testDefaults{system_test_reps});
我也会的。毕竟,这就是我的意思。然而,赋值运算符的优先级低于三元运算符。真正发生的是:

(exists $testOverrides{$testName}{reps}) 
    ? ($reps = $testOverrides{$testName}{reps}) : ($reps))
    = $testDefaults{system_test_reps});
因此,最后的赋值总是发生在
$reps

如果使用if/else,效果会更好:

if (exists $testOverrides{$testName}{reps}) {
   $reps = = $testOverrides{$testName}{reps};
}
else {
   $reps = $testDefaults{system_test_reps};
}
没有优先级问题,更容易阅读,而且同样有效。

我会这样做(我不介意使用三元运算符)


HTH

看起来我缺少的是括号。您对三元与if的输入得到了适当的注意。我在学习perl,所以目前我真的在努力理解而不是解决问题。@AdamS:这很公平——但在什么意义上使用if/else是解决问题的方法呢?首先,我会说这是最好的解决方案。对我来说,说“好吧,我会这么做,因为它有效”是一种避免学习为什么三元法不起作用的方法。学习中的一种变通方法。我很确定
/
是在5.10中引入的。@JonathanLeffler:.+1作为工作示例。此问题以前出现过,请参阅。可能重复的
$reps = exists($testOverrides{$testName}{reps}) ?
    $testOverrides{$testName}{reps}             :
    $testDefaults{system_test_reps};