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

时间:2017-07-23 06:58:38

标签: arrays function perl subroutine dereference

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

此代码......

RewriteEngine On

RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} off 
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://www.zanjan.org%{REQUEST_URI} [R=301,L,NE] 

RewriteRule ^([a-zA-Z]+)/rss\.xml/?$    rss.php/$1    [NC,L]
RewriteRule ^fa/(post|product|subject|gallery|poll)/([0-9]+)/([^/]*)/?$ /$1.php/$2 [NC,L]

RewriteRule ^fa/([^/]*)$ index.php/$1   [NC,L]

RewriteRule ^sitemap\.xml$ sitemap.php   [NC,L]

RewriteRule ^posts(/?)$ posts.php   [NC,L]

RewriteRule ^tag/([^/]*)/?$ /tag.php?value=$1     [NC,L]

RewriteRule ^cat/([0-9]+)/([^/]*)/?$ /tag.php?value=$2     [NC,L]

...有输出......

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";

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

我发现解决这个问题的唯一方法是仅使用参考:

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)

产生输出:

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";

是否可以取消引用指向数组的指针而不会使整个数组重复?或者我是否需要将其保留在参考表格中并在我想使用它时取消引用它?

4 个答案:

答案 0 :(得分:10)

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

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等语言不同,因为在这些语言中,变量仅描述数组对象,即对数组的引用,而不是数组的内容。

答案 1 :(得分:3)

使用实验性再制造功能:

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

但为什么不把它作为参考呢?对于数组而言,您无法对数组引用做任何事情。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

代码明确要求复制数据

my @a = @$aRef;

以创建新数组@a

我不清楚你的意思

  

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

如果在某些操作中需要所有值 - 制作另一个阵列,或打印出来,或将它们发送到sortmap ... - 那么数据可能会被复制,或者它可能会被复制如果那是由指针完成的话。如果数据被复制(即使只在堆栈上),那么它就像我们有一个数组一样,它实际上是“解除引用”。

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

如果您需要访问特定的元素(或切片),那么请解除它,不要创建新的数组。

但是,请不要@$aRef[0] = 0;,因为它恰好是合法的,而是由

中的任何一个
$$aRef[0] = 0;
$aRef->[0] = 0;

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