从函数返回哈希的最佳Perl实践是什么?

时间:2009-07-07 21:19:35

标签: perl hash reference

我正在考虑将返回数据的哈希引用传递给/从函数传递的最佳实践。

一方面,将输入值仅传递给函数并且只返回输出变量似乎很直观。但是,在Perl中传递哈希只能通过引用来完成,因此它有点乱,并且似乎更容易出错。

另一种方法是在输入变量中传递引用,但是必须在函数中处理它,并且可能不清楚什么是输入以及什么是返回变量。

关于此的最佳做法是什么?

返回对数组和散列的引用,然后取消引用它。

($ref_array,$ref_hash) = $this->getData('input');
@array = @{$ref_array};
%hash = %{$ref_hash};

将引用(@array,%hash)传递给将保存输出数据的函数。

$this->getData('input', \@array, \%hash);

7 个答案:

答案 0 :(得分:18)

只需返回参考。没有必要取消引用整体 哈希就像你在你的例子中所做的那样:

my $result = some_function_that_returns_a_hashref;
say "Foo is ", $result->{foo};
say $_, " => ", $result->{$_} for keys %$result;

我从未见过有人传入空引用来保存结果。这是Perl,而不是C。

答案 1 :(得分:10)

尝试通过说

来创建副本
my %hash = %{$ref_hash};

比使用hashref更危险。这是因为它只创建一个浅拷贝。这将使您认为可以修改哈希,但如果它包含引用,它们将修改原始数据结构。我觉得最好只传递引用并小心,但如果你真的想确保你有一份传入的引用,你可以说:

use Storable qw/dclone/;

my %hash = %{dclone $ref_hash};

答案 2 :(得分:5)

第一个更好:

my ($ref_array,$ref_hash) = $this->getData('input');

原因是:

  • 在第二种情况下,getData()需要 检查要制作的数据结构 确定它们是空的
  • 您可以自由地将undef作为特殊值返回
  • 它看起来更像Perl-idiomatic。

注意:行

@array = @{$ref_array};
%hash = %{$ref_hash};

是有问题的,因为你在这里浅层复制整个数据结构。您可以在需要数组/哈希的任何地方使用引用,使用 - >操作员为了方便起见。

答案 3 :(得分:4)

如果它变得足够复杂,那么callsite和被调用的函数都在为它付费(因为你每次使用它都需要思考/写入更多),为什么不只是使用一个对象呢?

my $results = $this->getData('input');

$results->key_value_thingies;
$results->listy_thingies;

如果使一个对象“太复杂”,那么就开始使用Moose,使它不再是。

答案 4 :(得分:1)

我个人对子接口的偏好:

  1. 如果例程有0-3个参数,则可以以列表形式传递它们:foo( 'a', 12, [1,2,3] );
  2. 否则传递名称值对列表。 foo( one => 'a', two => 12, three => [1,2,3] );
  3. 如果例程有或可能有多个参数,请认真考虑使用名称/值对。
  4. 传入引用会增加无意中修改数据的风险。

    在返回时,我通常更喜欢返回结果列表而不是数组或哈希引用。

    当它在速度或内存消耗方面(即BIG结构)显着改善时,或者当涉及复杂的数据结构时,我会返回散列或数组引用。

    在不需要时返回引用会剥夺其中一种利用Perl的良好列表处理功能的能力,并使其暴露于无意中修改数据的危险之中。

    特别是,我发现将结果列表分配到数组并返回数组很有用,该数组提供了数组的上下文返回行为。

    对于传入两个哈希的情况,我会做类似的事情:

    my $foo = foo( hash1 => \%hash1, hash2 => \%hash2 ); # gets number of items returned
    my @foo = foo( hash1 => \%hash1, hash2 => \%hash2 ); # gets items returned
    
    sub foo {
       my %arg = @_;
    
       # do stuff
    
       return @results;
    }
    

答案 5 :(得分:1)

我最初将此问题发布到另一个问题,然后有人将此指向“相关帖子”,因此我将在此处发布以表达我对该主题的看法,假设人们将来会遇到它。

我要反驳接受的答案并说我更喜欢将我的数据作为普通哈希返回(好吧,作为一个偶数大小的列表,很可能被解释为哈希)。我在一个我们倾向于执行以下代码片段之类的环境中工作,并且当您不必每隔一行取消引用时,它更容易组合和排序以及切片和切块。 (也很高兴知道有人不能破坏你的hashref,因为你按值传递了整个东西 - 虽然有人指出如果你的哈希包含的不仅仅是简单的标量,那就不那么简单了。)

my %filtered_config_slice = 
   hashgrep { $a !~ /^apparent_/ && defined $b } (
   map { $_->build_config_slice(%some_params, some_other => 'param') } 
   ($self->partial_config_strategies, $other_config_strategy)
);

这近似于我的代码可能做的事情:基于各种配置策略对象构建对象的配置(对象本身知道其中一些,加上一些额外的人),然后将其中一些过滤掉为无关。 / p>

(是的,我们有很好的工具,例如hashgrephashmap以及lkeys,可以对哈希做有用的事情。$ a和$ b设置为键和每个键的值列表中的项目,分别)。 (是的,我们有人可以在这个级别进行编程。招聘是令人讨厌的,但我们有一个优质的产品。)

如果你不打算做类似这样的函数式编程的任何事情,或者你需要更多的性能(你有没有分析?),那么确定,使用hashrefs。

答案 6 :(得分:0)

呃......“传递哈希只能通过引用来完成”?

sub foo(%) {
    my %hash = @_;
    do_stuff_with(%hash);
}

my %hash = (a => 1, b => 2);
foo(%hash);

我错过了什么?

我想说如果问题是你需要从一个函数中获得多个输出,那么最好输出一个数据结构,可能是一个哈希,它包含你需要发送的所有内容,而不是可以修改引用作为参数。