6

我有一个返回哈希的子程序。子程序的最后几行:

print Dumper(\%fileDetails);
return %fileDetails;

在这种情况下,倾卸器打印:

$VAR1 = {
          'somthing' => 0,
          'somthingelse' => 7.68016712043654,
          'else' => 'burst'
}

但是当我尝试转储它时,用这一行调用子例程:

print Dumper(\fileDetailsSub($files[$i]));

翻斗车打印:

$VAR1 = \'somthing';
$VAR2 = \0;
$VAR3 = \'somthingelse';
$VAR4 = \7.68016712043654;
$VAR5 = \'else';
$VAR6 = \'burst';

一旦哈希被破坏,我就不能再使用它了。为什么会这样?以及如何在子程序返回时保留正确的结构?

谢谢,马克。

4

5 回答 5

11

在 Perl 中没有返回哈希值这样的事情。

子例程将列表作为参数,并且可以返回列表作为结果。请注意,列表与数组是完全不同的生物。

当你写

return %fileDetails;

这相当于:

return ( 'something', 0, 'somethingelse', 7.68016712043654, 'else', 'burst' );

当您调用子例程并取回该列表时,您可以做的一件事是将其分配给一个新的哈希:

my %result = fileDetailsSub();

之所以可行,是因为可以使用键值对列表来初始化散列。(请记住,(foo => 42, bar => 43 )这与('foo', 42, 'bar', 43).

现在,当您在哈希上使用反斜杠引用运算符时,如在 中\%fileDetails,您将获得一个哈希引用,它是指向哈希的标量。

同样,如果你写\@array,你会得到一个数组引用。

但是当您在 list 上使用引用运算符时您不会获得对列表的引用(因为列表不是变量(它们是短暂的),它们不能被引用。)相反,引用运算符分布在列表项上, 所以

\( 'foo', 'bar', 'baz' );

创建一个新列表:

( \'foo', \'bar', \'baz' );

(在这种情况下,我们得到一个充满标量引用的列表。)这就是您在尝试处理Dumper子例程的结果时所看到的:一个引用运算符分布在从您的子程序返回的项目列表中。

因此,一种解决方案是在使用 Dumper 之前将结果列表分配给实际的哈希变量。另一个是从子返回一个哈希引用(无论如何你正在转储):

return \%fileDetails;

...

my $details_ref = fileDetailsSub();
print Dumper( $details_ref );

# access it like this:
my $elem = $details_ref->{something};
my %copy = %{ $details_ref };

更多乐趣,请参见:

于 2013-05-28T15:47:09.497 回答
8

为什么不返回对哈希的引用呢?

return \%fileDetails;

只要它是一个词法变量,它就不会使子程序的其他用途复杂化。IE:

sub fileDetails {
    my %fileDetails;
    ... # assign stuff
    return \%fileDetails;
}

当执行离开子例程时,变量超出范围,但内存中包含的数据仍然存在。

Dumper 输出看起来像这样的原因是您正在为其提供一个引用列表。子程序不能返回数组或散列,它们只能返回标量列表。你正在做的是这样的:

print Dumper \(qw(something 0 somethingelse 7.123 else burst));
于 2013-05-28T15:35:30.530 回答
3

Perl 函数不能返回哈希值,只能返回列表。return %foo语句将展平为%foo一个列表并返回展平的列表。要将返回值解释为散列,可以将其分配给命名散列

%new_hash = fileDetailsSub(...);
print Dumper(\%new_hash);

或使用一系列操作对其进行转换(不确定这是否是最好的词) :%{{...}}

print Dumper( \%{ {fileDetailsSub(...)} } );

正如 TLP 指出的那样,另一种方法是从您的函数中返回一个哈希引用。

于 2013-05-28T15:46:16.583 回答
1

您不能直接返回散列,但 perl 可以根据需要自动在散列和列表之间进行转换。因此 perl 将其转换为列表,并且您将其捕获为列表。IE

Dumper( filedetail() ) # list
my %fd = filedetail(); Dumper( \%fd ); #hash
于 2013-05-28T15:44:15.257 回答
0

在列表上下文中,Perl 不区分散列和键/值对列表。也就是说,如果一个子程序returnsa 哈希,它真正返回的是一个(key1, value1, key2, value2...). 幸运的是,这是双向的。如果您获取这样一个列表并将其分配给哈希,您将获得原始的忠实副本:

my %fileDetailsCopy = subroutineName();

但是,如果它不会破坏其他代码,那么让子返回对哈希的引用可能会更有意义,正如 TLP 所说。

于 2013-05-28T15:44:13.403 回答