【问题标题】:Perl: How do you dereference an array without creating a copy of the array?Perl:如何在不创建数组副本的情况下取消引用数组?
【发布时间】:2017-12-28 23:08:45
【问题描述】:

当我使用 @$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)

是否可以在不复制整个数组的情况下取消引用指向数组的指针?还是我需要将其保留为参考形式并在我想使用它的任何时候取消参考?

【问题讨论】:

    标签: arrays function perl subroutine dereference


    【解决方案1】:

    代码明确要求复制数据

    my @a = @$aRef;
    

    为了创建一个新数组@a

    我不清楚你的意思是什么

    是否可以在不复制整个数组的情况下取消引用指向数组的指针?

    如果在某些操作中需要所有值——创建另一个数组,或打印出来,或将它们发送到sortmap ...——那么数据可能会被复制,或者可能不会被复制由指针完成。如果数据被复制(即使只是在堆栈上),那么它就像我们有一个数组一样,它被有效地“取消引用”。

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


    如果您需要访问特定元素(或切片),请取消对它的引用,不要创建新数组。

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

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

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

    【讨论】:

    • 打印出来或发送到排序或映射不需要副本
    • @ysth 没有副本?是否不需要将值放在堆栈上才能使用它们? mapsort 不通过指针获取数据——或者是吗?我并不是说要创建一个新数组,只是要在后台复制数据(创建一个新列表,一次可能是一个元素)。感谢您的编辑。
    • @ysth 我的意思是,如果需要这些值,那么无论是否需要数组引用,它们都会被复制,并且“取消引用”与它无关。我有一个数组引用,但是当我将它提交给sort 时,数据就可用(在堆栈上?),就像我有一个数组一样。所以它被“取消引用”。在其他一些操作中可能不会——这取决于对数据的处理方式,一般来说不能说太多。 // 如果这是无意义的(或错误的),我将不胜感激。再说一次,我希望我不会打扰你,但这与很多事情息息相关。
    【解决方案2】:

    使用实验性的重锯齿功能:

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

    但是为什么不把它作为参考呢?数组没有什么是你不能用数组引用做的。

    【讨论】:

    • 这应该被接受。与其他一切不同,这是正确的答案。 (我刚刚发现了 refaliasing 并来到这里将其添加到我的答案中,但你比我早了一英里。)
    【解决方案3】:

    我的观察/理解是,它与名称有关——如果你为取消引用的数组命名,它将被复制,因为 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-Symbol-Table-Entries-(typeglobs)

    【讨论】:

    • 感谢您包含旧技术:) 谁知道,也许有一天会派上用场。 (可能不是大声笑)
    【解决方案4】:

    解引用不会创建副本,如下例所示:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-27
      • 2013-03-12
      • 2019-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 1970-01-01
      相关资源
      最近更新 更多