为什么三元条件运算符对于未定义的 hashref 键的行为与常规未定义的 $ 变量的行为不同?例如,如果 $form 未定义并且 $str 已定义,则以下三元组始终将 str 的值分配给 form 的值: ($str) ? $form = $str : $form = $form; 然而,如果未定义的哈希键被替换,它就不再起作用。
我制作了一个脚本来演示奇怪的行为。请注意,您将在所有测试中收到“使用未初始化值”警告。这是故意的,因为我正在测试未定义的值。提前致谢
#!/usr/bin/env perl
# ternary operator
# condition ? if True : if False
# Why does the ternary operator behave different with a undefined hashref key
# than a regular undefined $ variable ?
use strict;
use warnings;
use diagnostics;
my $i = 1;
my $form = { vc => 'customer', customer_id => ''};
my $ref = { customer_id => 12345 };
&string_test;# passes
print "-" x 80;
&mixed_test_ref; # passes
print "-" x 80;
&mixed_test; #fails
print "-" x 80;
&hashref_test; #fails
print "-" x 80;
&works_always;
print "-" x 80;
print "\n";
sub string_test {
my $str = '1234';
my $form; # not defined
print qq|
Why does the ternary operator behave different
with a undefined hashref key
than a regular undefined \$ variable ?
First with a undefined variable called form:
Before:
str : '$str' \n
form : $form
|; # will throw undefined warning
# ternary operator
#condition ? if True : if False
($str) ? $form = $str :
$form = $form;
print qq|
Always works:
str : '$str' \n
form: $form \n|;
}
sub mixed_test_ref {
my $local;
print qq|
Mixed test ref
Before:
form->{vc} '$form->{vc}' \n
ref->{"$form->{vc}_id"} : '$ref->{"$form->{vc}_id"}' \n
|;
# ternary operator
#condition ? if True : if False
($ref->{"$form->{vc}_id"}) ? $local = $ref->{"$form->{vc}_id"} :
$local = $local;
print qq|
After:
form->{vc} '$form->{vc}' \n
ref->{"$form->{vc}_id"} : '$ref->{"$form->{vc}_id"}' \n
local: '$local' \n
|;
if ($local = $ref->{"$form->{vc}_id"}) {print "Pass\n"}
else {print "Fail\n"}
}
sub mixed_test {
# $form->{"$form->{vc}_id_$i"} is not defined
# setting it to empty string makes it pass
#$form->{"$form->{vc}_id_$i"} = '';
delete $form->{"$form->{vc}_id_$i"};
my $str = '1234';
print qq|
mixed test
Before:
str : '$str' \n
form: '$form->{"$form->{vc}_id_$i"}' \n
|;
# ternary operator
#condition ? if True : if False
($str) ? $form->{"$form->{vc}_id_$i"} = $str :
$form->{"$form->{vc}_id_$i"} = $form->{"$form->{vc}_id_$i"};
if ( $form->{"$form->{vc}_id_$i"} == $str ) {
print qq|Pass\
After:
str : '$str' \n
form: $form->{"$form->{vc}_id_$i"} \n|;
}
else {print "Fail\n"}
}
sub hashref_test {
# $form->{"$form->{vc}_id_$i"} is not defined
# setting it to empty string makes it pass
#$form->{"$form->{vc}_id_$i"} = '';
delete $form->{"$form->{vc}_id_$i"};
print qq|
hash ref test
Before:
form->{vc} '$form->{vc}' \n
ref->{"$form->{vc}_id"} : '$ref->{"$form->{vc}_id"}' \n
form->{"$form->{vc}_id_$i"} : $form->{"$form->{vc}_id_$i"} \n
|;
# ternary operator
#condition ? if True : if False
$ref->{"$form->{vc}_id"} ? $form->{"$form->{vc}_id_$i"} = $ref->{"$form->{vc}_id"} :
$form->{"$form->{vc}_id_$i"} = $form->{"$form->{vc}_id_$i"};
if ($form->{"$form->{vc}_id_$i"}) {print "Passes and I am amazed\n"}
else {
print qq|
Why does this not work?
After:
form->{vc} '$form->{vc}' \n
ref->{"$form->{vc}_id"} : '$ref->{"$form->{vc}_id"}' \n
form->{"$form->{vc}_id_$i"} : $form->{"$form->{vc}_id_$i"} \n|;
}
}
sub works_always {
if ($ref->{"$form->{vc}_id"}) { $form->{"$form->{vc}_id_$i"} = $ref->{"$form->{vc}_id"} }
# not necessary but for completeness
else { $form->{"$form->{vc}_id_$i"} = $form->{"$form->{vc}_id_$i" } }
print qq|
Always works as expected with if statement:
form->{vc} '$form->{vc}' \n
ref->{"$form->{vc}_id"} : '$ref->{"$form->{vc}_id"}' \n
form->{"$form->{vc}_id_$i"} : $form->{"$form->{vc}_id_$i"} \n|;
}
Run Code Online (Sandbox Code Playgroud)
mob*_*mob 10
当我看到问题的标题时,我知道答案将是关于优先级的。
你可能会认为
($str) ? $form = $str : $form = $form;
Run Code Online (Sandbox Code Playgroud)
方法
if ($str) {
$form = $str;
} else {
$form = $form;
}
Run Code Online (Sandbox Code Playgroud)
但是这个命令
$ perl -MO=Deparse,-p -e '($str) ? $form = $str : $form = $form'
(($str ? ($form = $str) : $form) = $form);
Run Code Online (Sandbox Code Playgroud)
向我们表明这确实意味着
if ($str) {
$form = $str = $form;
} else {
$form = $form;
}
Run Code Online (Sandbox Code Playgroud)
这可以通过多种方式解决。加上更多括号:
($str) ? ($form = $str) : ($form = $form)
Run Code Online (Sandbox Code Playgroud)
或者写一个更简单的表达式:
$form = $str if $str;
$form = $str || $form;
Run Code Online (Sandbox Code Playgroud)