Ada*_*m S 7 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 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";
}
Run Code Online (Sandbox Code Playgroud)
这给出了以下输出:
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
Run Code Online (Sandbox Code Playgroud)
这个输出是最意想不到的!我不明白为什么第一个三元似乎总是在执行"if false"条款.它始终赋值为10.我也尝试将"false"子句更改为$reps = 6,并且我看到它总是得到值6.为什么三元的逻辑依赖于第三个(如果为假)子句的内容?
Kei*_*son 10
这是一个更简单的脚本来说明问题:
#!/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";
Run Code Online (Sandbox Code Playgroud)
它产生这个输出:
Without parentheses, $x = 0
With parentheses, $x = 1
Run Code Online (Sandbox Code Playgroud)
我不确定赋值之间的关系?:可以通过运算符优先级来完整解释.(例如,我相信在某些情况下C和C++的行为会有所不同.)
运行perldoc perlop并搜索"条件运算符",或者查看此处 ; 它涵盖了这个确切的问题(比我在这里更简洁).
在任何情况下,我认为使用if/ else语句比使用?:运算符更清晰.或者,由于"true"和"false"分支都分配给同一个变量,更好的用法?:是改变它:
exists $testOverrides{$testName}{reps}
? $reps = $testOverrides{$testName}{reps}
: $reps = $testDefaults{system_test_reps};
Run Code Online (Sandbox Code Playgroud)
对此:
$reps = ( exists $testOverrides{$testName}{reps}
? testOverrides{$testName}{reps}
: $testDefaults{system_test_reps} );
Run Code Online (Sandbox Code Playgroud)
但同样,我必须包裹线以避免滚动这一事实很好地表明if/else会更清晰.
您可能还会考虑使用//运算符,除非您遇到不支持它的古老版本的Perl.(它是由Perl 5.10引入的.)它也被称为"定义或"运算符.这个:
$x // $y
Run Code Online (Sandbox Code Playgroud)
相当于
defined($x) ? $x : $y
Run Code Online (Sandbox Code Playgroud)
所以你可以写:
$reps = $testOverrides{$testName}{reps} // $testDefaults{system_test_reps};
Run Code Online (Sandbox Code Playgroud)
这没有完全相同的语义,因为它使用defined而不是exists; 来测试表达式; 如果$testOverrides{$testName}{reps}存在,它将表现不同,但具有价值undef.
对于这样的问题,-p可以选择B::Deparse照明:
$ perl -MO=Deparse,-p -e '$condition ? $x = $value1 : $x = $value2'
(($condition ? ($x = $value1) : $x) = $value2);
Run Code Online (Sandbox Code Playgroud)
正如Keith Thompson指出的那样,这完全取决于优先级.如果条件为假,则最终分配为$x = $value2.如果条件为真,那么赋值是($x = $value1) = $value2- 结果是分配$value2给的$x.