11

我刚刚花了很多时间调试一个我追溯到wantarray(). 我已将其提炼为这个测试用例。(忽略$!在这种情况下不会有任何有用信息的事实)。我想知道的是为什么wantarray在第二个示例中不认为它在 LIST 上下文中被调用:

#!/usr/bin/env perl

use strict;
use warnings;
use Test::More;

{
    my ( $one, $two ) = foo();
    is( $one, 'a', 'just foo' );
    is( $two, 'b', 'just foo' );
}

{
    my ( $one, $two ) = foo() || die $!;
    is( $one, 'a', '|| die' );
    is( $two, 'b', '|| die' );
}


done_testing();

sub foo {
    return wantarray ? ( 'a', 'b' ) : 'bar';
}

这个测试的输出是:

$ prove -v wantarray.pl
wantarray.pl ..
ok 1 - just foo
ok 2 - just foo
not ok 3 - || die
not ok 4 - || die
1..4

#   Failed test '|| die'
#   at wantarray.pl line 15.
#          got: 'bar'
#     expected: 'a'

#   Failed test '|| die'
#   at wantarray.pl line 16.
#          got: undef
#     expected: 'b'
# Looks like you failed 2 tests of 4.
Dubious, test returned 2 (wstat 512, 0x200)
Failed 2/4 subtests

Test Summary Report
-------------------
wantarray.pl (Wstat: 512 Tests: 4 Failed: 2)
  Failed tests:  3-4
    Non-zero exit status: 2
    Files=1, Tests=4,  0 wallclock secs ( 0.03 usr  0.01 sys +  0.02 cusr  0.00 csys =  0.06 CPU)
    Result: FAIL
4

3 回答 3

9

因为它没有在列表上下文中被调用。||在其左侧施加标量上下文,在这种情况下,其左侧是表达式foo()

你应该改写

my ( $one, $two ) = foo() or die $!;

运算符的or绑定比赋值运算符还要松,所以现在它的 LHS 是整个表达式my ($one, $two) = foo(),而foo的上下文是由列表赋值运算符决定的,大家都很开心。

于 2013-07-08T21:41:33.387 回答
6

原因是由于||运算符的优先级。您的语句基本上是这样解析的:

my ( $one, $two ) = ( foo() || die $! );

在这种||情况下,将其操作数置于标量上下文中。

另一方面,如果您更改||or优先级低得多的 ,您的测试将通过。

于 2013-07-08T21:42:06.363 回答
4

逻辑或 ( ||) 是一个标量运算符,因此使用它将强制计算foo()成为标量上下文。

尝试这个:

my @a = 10 .. 100;
print(@a || 2), "\n";
# prints 91

@a如果不是因为数组已在标量上下文中评估,您会期望这会打印元素。

于 2013-07-08T21:40:41.733 回答