Perl:如何在不创建数组副本的情况下取消对数组的引用?
Perl: How do you dereference an array without creating a copy of the array?
当我使用@$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: @a\n";
print "inside1 $aRef: $aRef\n";
print "inside1 $aRef2: $aRef2\n";
print "inside1 $aRef3: $aRef3\n\n";
}
my @array = (1, 2);
print "before: @array\n";
my $ar = \@array;
print "before: $ar\n\n";
updateArray1(\@array);
print "after: @array\n";
$ar = \@array;
print "after: $ar\n\n";
...有输出...
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: @$aRef\n";
print "inside2 $aRef: $aRef\n\n";
}
updateArray2(\@array);
print "after2: @array\n";
$ar = \@array;
print "after2: $ar\n\n";
产生输出:
inside2 @$aRef: 0 2 3
inside2 $aRef: ARRAY(0x1601440)
after2: 0 2 3
after2: ARRAY(0x1601440)
是否可以在不复制整个数组的情况下取消对数组指针的引用?还是我需要以参考形式保存它并在我想使用它时随时取消引用?
我的 observation/understanding 是关于名称的——如果你给取消引用的数组一个名称,它将被复制,因为 perl 变量是通过复制传递的——它们就像中的结构C++。但即使引用被复制(这类似于 C/C++ 中的 int *newPtr = oldPtr
),引用的每个副本都将指向同一个对象。只有当您通过引用访问它的元素,或者通过内联取消引用它时,原始数组才会被修改。我认为没有任何办法解决这个问题。当您调用 my @foo = @{$barRef}
时,您正在调用一个复制构造函数。标量是相同的——当您通过 $_[0] = val
修改参数时,调用者的变量也会被修改。但是如果你给变量一个名字,a la my $arg = $_[0]
,就会创建一个副本。
也就是说,如果您还没有使用过引用,那么有一些您应该了解的便捷方法:
$arrayRef->[0] = "foo";
$hashRef->{key} = "value";
$codeRef->(); # execute a code reference
但实际上,由于 push
无法处理引用,您需要像示例中那样使用内联取消引用。
如果您真的非常想创建一个作为引用的数组,可以使用一种古老的 perl 技术来实现。你不应该在现代代码中使用它。此处描述:https://perldoc.perl.org/perlsub.html#Passing-Symbol-Table-Entries-(typeglobs)
取消引用不会创建副本,如下例所示:
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 等语言不同,因为在这些语言中,变量仅描述数组对象,即对数组的引用而不是数组的内容。
代码明确要求复制数据
my @a = @$aRef;
为了创建一个新数组@a
。
我不清楚你的意思
Is it possible to dereference a pointer to an array without the whole array getting duplicated?
如果在某些操作中需要所有值——创建另一个数组,或将它们打印出来,或将它们发送到 sort
或 map
... – 那么可以复制数据,或如果这是通过指针完成的,则可能不会。如果数据被复制(即使只在堆栈上),那么它就像我们有一个数组一样,它实际上是 "dereferenced."
这是一个关于如何处理数据的问题,一般不能说太多。
如果您需要访问特定元素(或切片),则取消引用它,不要创建新数组。
然而,请不要通过 @$aRef[0] = 0;
即使它恰好是合法的,而是通过
$$aRef[0] = 0;
$aRef->[0] = 0;
我发现第二个版本通常更安全、更清晰地防止愚蠢的错误。
使用实验性重新命名功能:
use 5.022;
use warnings;
use feature 'refaliasing';
no warnings 'experimental::refaliasing';
\my @array = $array_ref;
但为什么不把它留作参考呢?没有什么是你不能用数组做的,也不能用数组引用做的。
当我使用@$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: @a\n";
print "inside1 $aRef: $aRef\n";
print "inside1 $aRef2: $aRef2\n";
print "inside1 $aRef3: $aRef3\n\n";
}
my @array = (1, 2);
print "before: @array\n";
my $ar = \@array;
print "before: $ar\n\n";
updateArray1(\@array);
print "after: @array\n";
$ar = \@array;
print "after: $ar\n\n";
...有输出...
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: @$aRef\n";
print "inside2 $aRef: $aRef\n\n";
}
updateArray2(\@array);
print "after2: @array\n";
$ar = \@array;
print "after2: $ar\n\n";
产生输出:
inside2 @$aRef: 0 2 3
inside2 $aRef: ARRAY(0x1601440)
after2: 0 2 3
after2: ARRAY(0x1601440)
是否可以在不复制整个数组的情况下取消对数组指针的引用?还是我需要以参考形式保存它并在我想使用它时随时取消引用?
我的 observation/understanding 是关于名称的——如果你给取消引用的数组一个名称,它将被复制,因为 perl 变量是通过复制传递的——它们就像中的结构C++。但即使引用被复制(这类似于 C/C++ 中的 int *newPtr = oldPtr
),引用的每个副本都将指向同一个对象。只有当您通过引用访问它的元素,或者通过内联取消引用它时,原始数组才会被修改。我认为没有任何办法解决这个问题。当您调用 my @foo = @{$barRef}
时,您正在调用一个复制构造函数。标量是相同的——当您通过 $_[0] = val
修改参数时,调用者的变量也会被修改。但是如果你给变量一个名字,a la my $arg = $_[0]
,就会创建一个副本。
也就是说,如果您还没有使用过引用,那么有一些您应该了解的便捷方法:
$arrayRef->[0] = "foo";
$hashRef->{key} = "value";
$codeRef->(); # execute a code reference
但实际上,由于 push
无法处理引用,您需要像示例中那样使用内联取消引用。
如果您真的非常想创建一个作为引用的数组,可以使用一种古老的 perl 技术来实现。你不应该在现代代码中使用它。此处描述:https://perldoc.perl.org/perlsub.html#Passing-Symbol-Table-Entries-(typeglobs)
取消引用不会创建副本,如下例所示:
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 等语言不同,因为在这些语言中,变量仅描述数组对象,即对数组的引用而不是数组的内容。
代码明确要求复制数据
my @a = @$aRef;
为了创建一个新数组@a
。
我不清楚你的意思
Is it possible to dereference a pointer to an array without the whole array getting duplicated?
如果在某些操作中需要所有值——创建另一个数组,或将它们打印出来,或将它们发送到 sort
或 map
... – 那么可以复制数据,或如果这是通过指针完成的,则可能不会。如果数据被复制(即使只在堆栈上),那么它就像我们有一个数组一样,它实际上是 "dereferenced."
这是一个关于如何处理数据的问题,一般不能说太多。
如果您需要访问特定元素(或切片),则取消引用它,不要创建新数组。
然而,请不要通过 @$aRef[0] = 0;
即使它恰好是合法的,而是通过
$$aRef[0] = 0;
$aRef->[0] = 0;
我发现第二个版本通常更安全、更清晰地防止愚蠢的错误。
使用实验性重新命名功能:
use 5.022;
use warnings;
use feature 'refaliasing';
no warnings 'experimental::refaliasing';
\my @array = $array_ref;
但为什么不把它留作参考呢?没有什么是你不能用数组做的,也不能用数组引用做的。