来自sub的perl返回值混淆了

时间:2013-07-12 14:10:36

标签: perl hashtable

我正试图从perl中的sub获得2个不同的哈希值。哈希在子的输出中混淆。这是我的简化代码:

#!/usr/bin/perl

use strict;
use warnings;

sub sub1 {
    my (%h1, %h2);
    $h1{'1a'}++;
    $h1{'1b'}++;
    $h2{'2a'}++;
    $h2{'2b'}++;
    while ( (my $key, my $value) = each %h1 ){
        print "key: $key, value: $value\n";
    }
    print "\n";
    return (%h1, %h2);
}

my (%r1, %r2) = sub1();
while ( (my $key, my $value) = each %r1 ){
    print "key: $key, value: $value\n";
}

输出:

key: 1b, value: 1
key: 1a, value: 1

key: 1b, value: 1
key: 2a, value: 1
key: 2b, value: 1
key: 1a, value: 1

为什么会这样?我该如何纠正?感谢。

2 个答案:

答案 0 :(得分:10)

Perl正在将您的两个哈希值合并为一个并将它们存储在%r1变量中,除非您从子例程中返回引用,否则始终会发生。

sub sub1 {
    my (%h1, %h2);
    $h1{'1a'}++;
    $h1{'1b'}++;
    $h2{'2a'}++;
    $h2{'2b'}++;
    while ( (my $key, my $value) = each %h1 ){
        print "key: $key, value: $value\n";
    }
    print "\n";
    return (\%h1, \%h2); # \(backslash) creates a hashref
}

然后你需要在标量变量中存储这些引用:

my ($r1, $r2) = sub1(); # scalar variables with references to %h1 and %h2

# use %{ } to put $r1 in hash context
while ( (my $key, my $value) = each %{ $r1 } ){
    print "key: $key, value: $value\n";
}

# prints 
# key: 1b, value: 1
# key: 1a, value: 1

# key: 1b, value: 1
# key: 1a, value: 1

答案 1 :(得分:2)

您可能应该阅读references

Perl子例程可以获取参数列表并返回列表。例如,如果我这样做:

array_sub ( @a, @b );

sub array_sub {
    return print join ( ": ", @_ ) . "\n";
}

你会注意到,传递的两个数组将被合并到一个参数列表中,而无法分辨一个列表的开始位置和另一个列表的结束位置。

哈希发生类似的事情:

array_sub ( %a, %b );

sub array_sub {
    return print join ( ": ", @_ ) . "\n";
}

这会将两个哈希(及其键)合并为一个传递给子例程的列表。

要解决此限制,您可以使用 references ,它们基​​本上是标量值,指向实际数组或哈希所在的内存位置:

array_sub { \@a, \@b );

sub array_sub {
    my $ref_a = shift;
    my $ref_b = shift;
    my @sub_a = @{ $ref_a };
    my @sub_b = @{ $ref_b };

在上面,我在数组前放了一个反斜杠,以获得引用到数组。要取消引用它们(即将它们变回数组),我将@{...}放在引用周围。

您必须在代码中执行类似的操作:

my ($r1, $r2) = sub1();   #Returns references;
my @r1 = @{ $r1 };   #dereference
my @r2 = @{ $r2 };   #dereference

在您的子程序中:

sub sub1 {
    ...
    return \%h1, \%h2;