Perl 条件(三元)运算符不执行快捷方式计算

U. *_*ndl 28 perl conditional-operator

条件(三元)运算符表明三元运算符是if...的替代品else。我一直这么认为,但最近我有一个逻辑问题。

考虑这个简短的调试会话:

  DB<1> $s='X'

  DB<2>  1 ? $s .= '_' : $s = '_'

  DB<3> x $s
0  '_'
Run Code Online (Sandbox Code Playgroud)

因此,如果为 true,则应该计算1表达式(而不是)。$s .= '_'$s = '_'

但为什么$s只是'_'最后呢?

Dad*_*ada 47

三元条件运算符 ( ?:) 的优先级高于赋值运算符 ( ) (Perl 运算符的优先级表可以在 perlop 的运算符优先级和结合性=一节中找到)。因此,该行

1 ? $s .= '_' : $s = '_'
Run Code Online (Sandbox Code Playgroud)

由 Perl 解析为

(1 ? ($s .= '_') : $s) = '_'
Run Code Online (Sandbox Code Playgroud)

(您可以通过运行自行检查perl -MO=Deparse <your program>

另请注意,$s .= '_'返回时会在末尾$s添加,并且可以将其分配给(用技术术语来说,它是一个左值)。这记录在perlop 的赋值运算符部分:_$s

与 C 不同,标量赋值运算符生成有效的左值。修改赋值相当于执行赋值,然后修改被赋值的变量。

所以,基本上,你的代码正在做

($s .= '_') = '_';
Run Code Online (Sandbox Code Playgroud)

这相当于

$s .= '_';
$s = '_';
Run Code Online (Sandbox Code Playgroud)

  • 通常,您使用三元运算符来分配结果,而不是在“分支”中分配,这是有意义的。因此,运算符的优先级适合这种情况,但在我的情况下,在分支中使用赋值时,我需要括号。我的错。 (2认同)

mob*_*mob 18

这是一个运算符优先级的问题。

$ perl -MO=Deparse,-p -e '   
> $s='X';
> $t=1;
> $t ? $s .= '_' : $s = '_';
> print $s'
($s = 'X');
($t = 1);
(($t ? ($s .= '_') : $s) = '_');
print($s);
-e syntax OK
Run Code Online (Sandbox Code Playgroud)

无论三元条件为真还是假,最终都$s设置为"_"

要执行您想要执行的操作,您需要添加至少一组括号:

1 ? $s .= '_' : ($s = '_');
Run Code Online (Sandbox Code Playgroud)


ike*_*ami 15

条件运算符仅评估必要的内容,但存在优先级问题。


首先,条件运算符确实保证使用短路评估,这意味着它只评估必要的内容。

$ perl -M5.010 -e'
   sub f { say "f" }
   sub g { say "g" }
   $ARGV[0] ? f() : g();
' 0
f

$ perl -M5.010 -e'
   sub f { say "f" }
   sub g { say "g" }
   say $ARGV[0] ? f() : g();
' 1
g
Run Code Online (Sandbox Code Playgroud)

E1 || E2对于、E1 or E2E1 && E2和来说也是如此E1 and E2。他们仅在必要时评估右侧操作数。

$ perl -M5.010 -e'
   sub f { say "f"; $ARGV[0] }
   sub g { say "g"; $ARGV[1] }
   say f() || g();
' 3 4
f
3

$ perl -M5.010 -e'
   sub f { say "f"; $ARGV[0] }
   sub g { say "g"; $ARGV[1] }
   say f() || g();
' 0 4
f
g
4
Run Code Online (Sandbox Code Playgroud)

这就是为什么您可以open(...) or die(...)安全地进行评估。在不短路的情况下,它会评估die是否open成功。


现在,我们来解释一下:

$s = "X";   1 ? $s .= "_" : $s = "_";         say $s;   # _
Run Code Online (Sandbox Code Playgroud)

这是一个优先级问题。上面相当于

$s = "X";   ( 1 ? ($s .= "_") : $s ) = "_";   say $s;   # _
Run Code Online (Sandbox Code Playgroud)

$s .= "_"返回$s,因此条件运算符返回$s,因此字符串_被分配给$s。如果我们添加括号来获得所需的解析,我们就会得到预期的结果。

$s = "X";   1 ? ($s .= "_") : ($s = "_");     say $s;   # X_
Run Code Online (Sandbox Code Playgroud)

选择:

$s = "X";   $s = ( 1 ? $s : "" ) . "_";       say $s;   # X_
Run Code Online (Sandbox Code Playgroud)