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

发布于 2024-08-03 05:47:52 字数 864 浏览 3 评论 0原文

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

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

[...]

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

<前><代码>@a = @b || @c; # 这是错误的 @a = 标量(@b) || @c; # 真正的意思是这个 @a=@b? @b:@c; # 不过这工作得很好

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

我期望发生的是这样的:

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

显然,我倒数第二个说法是错误的。为什么?而且,更重要的是,文档或来源的哪一部分解释了这种行为?

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

I'd like to perform some convoluted variation of the @a = @b || @c assignment, with the intent of taking @b if non-empty (hence true in a boolean sense), @c otherwise. The documentation explicitely tells me I can't. (And it's right about the fact, too!)

The "||", "//" and "&&" operators return the last value evaluated
(unlike C's "||" and "&&", which return 0 or 1).

[...]

In particular, this means that you shouldn't use this for selecting
between two aggregates for assignment:

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

Unfortunately, it doesn't really tell me why.

What I expected would happen was this:

  • @a = is an array assignment, inducing list context on the right hand side.
  • @b || @c is the right hand side, to be evaluated in list context.
  • || is C-style short-circuit logical or. It evaluates left to right (if needed) and propagates context.
  • @b is evaluated in list context. If true (i.e., non-empty), it is returned.
  • if not, @c is evaluated in list context as well, and returned.

Obviously, my penultimate statement is wrong. Why? And, more importantly, which part of the documentation or sources account for this behavior?

PS: out of the question's scope, the reason I refrain from the documentation's suggestion of using the ternary operator is that my @b is actually a temporary (a function call result).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦年海沫深 2024-08-10 05:47:52

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

它这样做的原因是为了弄清楚这个论点是否正确。布尔上下文是标量上下文的特例,强制其进入标量上下文。


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

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


来自 perldoc perldata "标量值":

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

The logical-or operator ( "||" ) evaluates its left hand argument in scalar context.

The reason it does this is to figure out if the argument is true. Boolean context, being a special case of scalar context, forces it into scalar context.


From perldoc perlop "C-style-Logical-Or"

Binary "||" performs a short-circuit logical OR operation. That is, if the left operand is true, the right operand is not even evaluated. ...


From perldoc perldata "Scalar values":

.... The Boolean context is just a special kind of scalar context where no conversion to a string or a number is ever performed.

烧了回忆取暖 2024-08-10 05:47:52

在 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.

因此我们可以假设传播到右操作数的列表上下文是这
该规则的例外情况,并且缺乏有关上下文的任何声明
左操作数意味着适用一般规则。

In perlop, just a few paragraphs before the section you quote:

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.

This doesn't explicitly state that list context does not propagate to the left operand, but the top of perlop states:

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

so we can assume that list context propagating to the right operand is the
exception to the rule, and the lack of any statement about the context of
the left operand implies the general rule applies.

奈何桥上唱咆哮 2024-08-10 05:47:52

正是因为 ||在标量上下文中计算左侧,就像 ?: 的测试参数一样。
如果不能使用三元,请使用函数:

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

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

It's because || evaluates the left side in scalar context, as does the test argument of ?: .
If you can't use the ternary, use a function:

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

@a = or_array(@b, @c);
万劫不复 2024-08-10 05:47:52

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

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

根据上面的答案,您的代码不起作用,因为 || 左侧的逻辑上下文在标量上下文中求值,因此 @b 实际上变成了 scalar(@b),这就是分配给 @a 的内容。

If you can't use the conditional operator directly, you can easily use the slightly-less-terse:

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

As per above answer, your code does not work since the logical context that the left side of || is evaluated in is a scalar context and thus @b actually becomes scalar(@b) and that is what gets assigned to @a.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文