为什么我不能分配@b ||在Perl中@c到@a?

时间:2009-08-31 14:12:34

标签: perl grammar

我想执行@a = @b || @c赋值的一些复杂变体,如果非空,则意图取@b(因此在布尔意义上为真),否则@c 。文档明确告诉我,我不能。 (而且事实也是正确的!)

  

“||”,“//”和“&&”运算符返回最后评估的值   (与C的“||”和“&&”不同,它返回0或1)。

     

[...]

     

特别是,这意味着您不应该使用它来进行选择   在两个聚合之间进行分配:

@a = @b || @c;              # this is wrong
@a = scalar(@b) || @c;      # really meant this
@a = @b ? @b : @c;          # this works fine, though

不幸的是,它并没有真正告诉我原因。

我期望会发生的事情是:

  • @a =是一个数组赋值,在右侧引入列表上下文。
  • @b || @c是右侧,需要在列表上下文中进行评估。
  • ||是C风格的短路逻辑或。它从左到右进行评估(如果需要)并传播上下文。
  • @b在列表上下文中进行评估。如果为真(,非空),则返回。
  • 如果没有,@c也会在列表上下文中进行评估,并返回。

显然,我的倒数第二句话是错误的。为什么?更重要的是,文档或来源的哪一部分可以解释这种行为?

PS:出于问题的范围,我不遵守文档关于使用三元运算符的建议的原因是我的@b实际上是临时的(函数调用结果)。

4 个答案:

答案 0 :(得分:7)

逻辑或运算符(“||”)在标量上下文中计算其左手参数。

这样做的原因是要弄清楚参数是否为真。布尔上下文是标量上下文的一个特例,它强制它进入标量上下文。


来自perldoc perlop "C-style-Logical-Or"

  

二进制“||”执行短路逻辑OR运算。也就是说,如果左操作数是 true ,则甚至不评估右操作数。 ...


来自perldoc perldata "Scalar values"

  

....布尔上下文只是一种特殊的标量上下文,不会转换为字符串或数字。

答案 1 :(得分:7)

在perlop中,在您引用的部分之前只有几个段落:

Binary "||" performs a short-circuit logical OR operation.  That is,
if the left operand is true, the right operand is not even evaluated.
Scalar or list context propagates down to the right operand if it is
evaluated.

这没有明确说明列表上下文不会传播到左操作数,而是perlop的顶部状态:

With very few exceptions, these all operate on scalar values
only, not array values.

所以我们可以假设传播到右操作数的列表上下文是 规则的例外,以及缺乏关于上下文的任何陈述 左操作数意味着适用一般规则。

答案 2 :(得分:2)

这是因为||在标量上下文中评估左侧,与?的测试参数一样。 如果您不能使用三元组,请使用函数:

sub or_array (\@\@) {
  return @{$_[0]} if ( scalar @{$_[0]} );
  return @{$_[1]};
}

@a = or_array(@b, @c);

答案 3 :(得分:0)

如果你不能直接使用条件运算符,你可以轻松地使用稍微简洁:

my $ref_b = [ @b ]; # Ideally, just return an arrayref from your function
my @a = @$ref_b ? @$ref_b : @c;

根据上面的回答,你的代码不起作用,因为评估||左侧的逻辑上下文是一个标量上下文,因此@b实际上变为scalar(@b)被分配给@a的内容。