我对以下内容感到困惑 有时我会看到这样的例子:
my %hash = get_data();
sub get_data {
my %data = ();
# do processing
return %data;
}
与数组类似。
my @arrays = get_data();
sub get_data {
my @data = ();
# do processing
return @data;
}
我原本以为你不能从函数返回数组或哈希只引用它们 所以我不明白有什么区别,我们什么时候应该优先于另一方呢? 它与垃圾收集或我们选择的数据副本太多有关吗?
答案 0 :(得分:11)
严格地说,您不能从Perl子例程返回数组或哈希。 Perl子例程返回列表。列表类似于数组,因为它们是值的序列,但它们不是数组。数组是变量。列表是无名,不可变和瞬态数据结构,用于传递和返回值,初始化数组和散列等。它是somewhat subtle point,但是很重要。
当你写return @data
时,你没有返回@data
数组;您将返回其包含的值列表。类似地,return %data
返回散列中包含的键/值对的列表。这些值可用于初始化另一个数组或散列,这正是您的示例中发生的情况。初始化的数组/哈希包含子例程使用的副本的(浅)副本。
要“返回”数组或散列,必须返回对它的引用。例如return \@data
或return \%data
。这样做会返回对变量本身的引用。修改它也会影响原始数组,因为它是相同的存储。
sub是否应该将数组/散列作为列表(副本)或引用返回是编程决策。对于总是返回具有位置意义的N值的subs(例如内置localtime
),返回列表是有意义的。对于返回任意大型列表的subs,通常最好返回一个引用,因为它更有效。
甚至可以让sub根据使用wantarray
调用的方式来决定返回什么。这让打电话者决定他们想要什么。
sub get_data {
my @data;
...
return wantarray ? @data : \@data;
}
my $aref = get_data(); # returns a reference
my @array = get_data(); # returns a list
答案 1 :(得分:3)
您实际上是在创建一个新数组(或哈希),其中填充的元素与在子数据库中生成的元素相同:
sub get_data{
# initialize an array
my @toReturn = qw/ a b c d e f g /;
# get its location in memory
my $toReturn_ref = \@toReturn;
# print its location in memory
print "toReturn: $toReturn_ref\n";
# return the **elements** in the array (not the array itself)
return @toReturn;
}
# initialize an array
my @arr = get_data();
# get its location in memory
my $arr_ref = \@arr;
# print its location in memory
print "\"Returned\": $arr_ref\n";
这将打印如下内容:
toReturn: ARRAY(0x1df85e8)
"Returned": ARRAY(0x1debc40)
它们是不同的数组,但恰好具有相同的内容。