我正在考虑将返回数据的哈希引用传递给/从函数传递的最佳实践。
一方面,将输入值仅传递给函数并且只返回输出变量似乎很直观。但是,在Perl中传递哈希只能通过引用来完成,因此它有点乱,并且似乎更容易出错。
另一种方法是在输入变量中传递引用,但是必须在函数中处理它,并且可能不清楚什么是输入以及什么是返回变量。
关于此的最佳做法是什么?
返回对数组和散列的引用,然后取消引用它。
($ref_array,$ref_hash) = $this->getData('input');
@array = @{$ref_array};
%hash = %{$ref_hash};
将引用(@array,%hash)传递给将保存输出数据的函数。
$this->getData('input', \@array, \%hash);
答案 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');
原因是:
注意:行
@array = @{$ref_array};
%hash = %{$ref_hash};
是有问题的,因为你在这里浅层复制整个数据结构。您可以在需要数组/哈希的任何地方使用引用,使用 - >操作员为了方便起见。
答案 3 :(得分:4)
如果它变得足够复杂,那么callsite和被调用的函数都在为它付费(因为你每次使用它都需要思考/写入更多),为什么不只是使用一个对象呢?
my $results = $this->getData('input');
$results->key_value_thingies;
$results->listy_thingies;
如果使一个对象“太复杂”,那么就开始使用Moose,使它不再是。
答案 4 :(得分:1)
我个人对子接口的偏好:
foo( 'a', 12, [1,2,3] );
foo( one => 'a', two => 12, three => [1,2,3] );
传入引用会增加无意中修改数据的风险。
在返回时,我通常更喜欢返回结果列表而不是数组或哈希引用。
当它在速度或内存消耗方面(即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>
(是的,我们有很好的工具,例如hashgrep
和hashmap
以及lkeys
,可以对哈希做有用的事情。$ a和$ b设置为键和每个键的值列表中的项目,分别)。 (是的,我们有人可以在这个级别进行编程。招聘是令人讨厌的,但我们有一个优质的产品。)
如果你不打算做类似这样的函数式编程的任何事情,或者你需要更多的性能(你有没有分析?),那么确定,使用hashrefs。
答案 6 :(得分:0)
呃......“传递哈希只能通过引用来完成”?
sub foo(%) {
my %hash = @_;
do_stuff_with(%hash);
}
my %hash = (a => 1, b => 2);
foo(%hash);
我错过了什么?
我想说如果问题是你需要从一个函数中获得多个输出,那么最好输出一个数据结构,可能是一个哈希,它包含你需要发送的所有内容,而不是可以修改引用作为参数。