2013-07-08 11 views
11

Ho appena trascorso un po 'di tempo per eseguire il debug di un problema risalente a wantarray(). L'ho distillato in questo caso di test. (Ignorare il fatto che $! non avrà alcuna informazione utile in questo scenario). Quello che mi piacerebbe sapere è perché wantarray non pensa che viene chiamato in contesto di lista nel secondo esempio:Perché wantarray restituisce in contesto scalare quando chiama foo() || morire?

#!/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'; 
} 

L'uscita di questo test è:

$ 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 
+1

+1 domanda scritta bene –

risposta

9

Perché non viene chiamato nel contesto dell'elenco. || impone il contesto scalare sul lato sinistro e in questo caso il lato sinistro è l'espressione foo().

si dovrebbe scrivere invece

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

L'operatore or si lega ancora più liberamente di quanto l'operatore di assegnazione, così ora la sua LHS è l'intera espressione my ($one, $two) = foo(), e il contesto foo s' è determinato dal l'operatore di assegnazione lista, e tutti sono felici.

4

logico o (||) è un operatore scalare, quindi utilizzarlo costringerà la valutazione di foo() a diventare un contesto scalare.

Prova questa:

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

ci si aspetterebbe questo per stampare gli elementi in @a se non fosse perché la matrice è stata valutata in un contesto scalare.

6

Il motivo è dovuto alla precedenza dell'operatore ||. La sua dichiarazione è fondamentalmente analizzato in questo modo:

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

Il || mette i suoi operandi in un contesto scalare in questo caso.

D'altra parte, se si modifica || in or, che ha una precedenza molto più bassa, i test passeranno.

+0

Grazie mille per questo. :) Era una specie di disapprovazione per scegliere una risposta accettata, ma quella che @hobbs ha fornito mi sembra un po 'più chiara. – oalders

Problemi correlati