我有以下代码:
# 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.为什么三元的逻辑取决于第三个的内容(如果虚假)条款?
解决方法
这是一个更简单的脚本来说明问题:
#!/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并搜索“条件运算符”,或查看here;它涵盖了这个确切的问题(比我在这里更简洁).
在任何情况下,我认为使用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会更清晰.
您可能还会考虑使用//运算符,除非您遇到不支持它的古老版本的Perl. (它是由Perl 5.10引入的.)它也被称为“定义或”运算符.这个:
$x // $y
相当于
defined($x) ? $x : $y
所以你可以写:
$reps = $testOverrides{$testName}{reps} // $testDefaults{system_test_reps};
这没有完全相同的语义,因为它使用defined而不是exists来测试表达式;如果$testOverrides {$testName} {reps}存在但值为undef,它的行为会有所不同.