perl subroutine returning array and str but they a

2020-04-21 07:55发布

问题:

sub process_feed {
    my ($line) = @_; 

    my @lines;
    my $last_received = ""; 

    while (1) {
        if ($line =~/^{(.*?)}(.*)/) {
            push @lines, $1; 
            $line = $2; 
        } else {
            $last_received = $line;
            last;
        }   
    }   

    print "sending back @lines, $last_received\n";

    return (@lines, $last_received);
}

my (@lines, $leftover) = process_feed("{hi1}{hi2}{hi3");
print "got lines: @lines\n";
print "got last_recevied, $leftover\n";

OUTPUT:

sending back hi1 hi2, {hi3
got lines: hi1 hi2 {hi3
got last_recevied, 

EXPECTED:

sending back hi1 hi2, {hi3
got lines: hi1 hi2 
got last_recevied, {hi3

why did $last_recevied get merged to @lines?
how do i split them in the outer func?

回答1:

A function returns a flat list. If an array is first in the list of variables being assigned to, the whole list goes into that array. So in

my (@lines, $leftover) = process_feed("{hi1}{hi2}{hi3");

the @lines gets everything that the sub returned.

Solutions

  • Return a reference to an array along with a scalar, so assign to two scalars

    sub process_feed { 
         # ...
         return \@lines, $last_received;
     }
     my ($rlines, $leftover) = process_feed("{hi1}{hi2}{hi3");
     print "got lines: @$rlines\n";
    

    I would recommend this approach, in general.

  • Since $last_received is always returned, swap the order in the return and assignment

    sub process_feed { 
        # ...
        return $last_received, @lines;
    }
    my ($leftover, @lines) = process_feed("{hi1}{hi2}{hi3"); 
    

Since the assignment is to a scalar first only one value from the return is assigned to it and then others go into next variables. Here it is the array @lines, which takes all remaining return.