Perl:如何在不创建数组副本的情况下取消引用数组?



当我使用 @$arrayRef 或 @{$arrayRef} 取消引用数组时,它似乎创建了数组的副本。 有没有正确的方法来取消引用数组?

此代码...

sub updateArray1 {
my $aRef = shift;
my @a = @$aRef;
my $aRef2 = @a;
$a[0] = 0;
push(@a, 3);
my $aRef3 = @a;
print "inside1 @a: @an";
print "inside1 $aRef: $aRefn";
print "inside1 $aRef2: $aRef2n";
print "inside1 $aRef3: $aRef3nn";
}
my @array = (1, 2);
print "before: @arrayn";
my $ar = @array;
print "before: $arnn";
updateArray1(@array);
print "after: @arrayn";
$ar = @array;
print "after: $arnn";

。有输出...

before: 1 2
before: ARRAY(0x1601440)
inside1 @a: 0 2 3
inside1 $aRef: ARRAY(0x1601440)
inside1 $aRef2: ARRAY(0x30c1f08)
inside1 $aRef3: ARRAY(0x30c1f08)
after: 1 2
after: ARRAY(0x1601440)

如您所见,@$aRef 创建了一个新的指针地址。

我发现解决此问题的唯一方法是仅使用引用:

sub updateArray2 {
my $aRef = shift;
@$aRef[0] = 0;
push(@$aRef, 3);
print "inside2 @$aRef: @$aRefn";
print "inside2 $aRef: $aRefnn";
}
updateArray2(@array);
print "after2: @arrayn";
$ar = @array;
print "after2: $arnn";

这会产生输出:

inside2 @$aRef: 0 2 3
inside2 $aRef: ARRAY(0x1601440)
after2: 0 2 3
after2: ARRAY(0x1601440)

是否可以取消引用指向数组的指针而不会复制整个数组? 还是我需要将其保留为引用形式并在我想使用它时取消引用它?

取消引用不会创建副本,如以下示例所示:

my @a = qw(a b c);
my $ra = @a;
@{$ra}[0,1] = qw(foo bar);  # dereferencing is done here but not copying
print @$ra; # foo bar c
print @a; # foo bar c

相反,(取消引用的(数组分配给另一个数组会创建副本

my @a = qw(a b c);
my $ra = @a;
my @newa = @$ra;   # copy by assigning
$newa[0] = 'foo';
print @newa; # foo b c
print @a; # a b c

将一个数组分配给另一个数组本质上意味着旧数组中的所有元素也应该分配给新数组 - 这与原始数组的名称不同。但是将一个数组引用分配给另一个数组只会使旧数组具有不同的名称,即复制数组引用与复制数组内容。

请注意,这似乎与Python或Java等语言不同,因为在这些语言中,变量仅描述数组对象,即对数组的引用而不是数组的内容。

使用实验性的别名功能:

use 5.022;
use warnings;
use feature 'refaliasing';
no warnings 'experimental::refaliasing';
my @array = $array_ref;

但为什么不把它作为参考呢? 对数组执行任何操作都不能对数组引用执行

任何操作。

代码显式要求复制数据

my @a = @$aRef;

为了创建一个新的数组@a

我不清楚你的意思

是否可以取消引用指向数组的指针而不会复制整个数组?

如果在某些操作中需要所有值 - 制作另一个数组,或打印出来,或将它们发送到sortmap......– 然后数据可能会被复制,或者如果通过指针完成,则可能不会。如果数据被复制(即使仅在堆栈上(,那么它就像我们有一个数组一样,它实际上是"取消引用"的。

这是一个如何处理数据的问题,一般不能说太多。


如果您需要访问特定元素(或切片(,请不要创建新数组。

但是,请不要通过@$aRef[0] = 0;,即使它恰好是合法的,而是通过以下任何一种

$$aRef[0] = 0;
$aRef->[0] = 0;

我发现第二个版本通常对愚蠢的错误更安全,而且更清晰。

我的观察/理解是,这是关于名称的——如果你给取消引用的数组起一个名字,它就会被复制,因为perl变量是通过复制传递的——它们就像C++中的结构一样。但是,即使复制了引用(这类似于 C/C++ 中的int *newPtr = oldPtr(,引用的每个副本也将指向同一对象。仅当您通过引用或通过内联取消引用来访问其元素时,才会修改原始数组。我认为没有任何办法解决这个问题。当您调用my @foo = @{$barRef}时,您正在调用复制构造函数。标量是相同的 - 当你通过$_[0] = val修改参数时,调用者的变量也会被修改。但是,如果您为变量命名,则my $arg = $_[0],则会制作副本。

也就是说,如果您尚未使用引用,则有一些方便的方法可以使用您应该了解的引用:

$arrayRef->[0] = "foo";
$hashRef->{key} = "value";
$codeRef->(); # execute a code reference

但实际上,由于push无法处理引用,因此您需要像在示例中那样使用内联取消引用。

如果你真的,真的想创建一个作为引用的数组,有一个旧的perl技术可以做到这一点。不应在新式代码中使用它。下面描述:https://perldoc.perl.org/perlsub.html#Passing-符号-表-条目-(类型(

最新更新