我可以在Perl中给匿名数组命名吗?

5
#!/usr/bin/perl -w

use strict;

my $aref = [1, 2, 3];
my @a = @$aref;              # this line
$a[1] = 99;
print "aref = @$aref\n";
print "a = @a\n";

生成输出:
aref = 1 2 3
a = 1 99 3

输出结果表明,@a@$aref不指向同一个数组。
问题出在标记行。标量$aref的值是匿名数组的引用。在标记行,我希望能够让数组变量@a指向该数组,但实际上发生的是,匿名数组被复制了,@a指向匿名数组的副本。赋值语句和打印语句都证明了这一点。
我知道当你对数组进行赋值时,赋值语句的右侧是列表上下文,因此@$aref被强制转换为其元素的列表。有没有一种方法可以将名称@a赋给$aref所引用的数组?

1
仅使用@$aref有什么问题吗? - ThisSuitIsBlackNot
2
@NormanofAnstruther 这就是为什么我留下了评论而不是答案。如果你解释一下为什么想要做某事,而不仅仅是如何做,通常可以得到更好的答案。 - ThisSuitIsBlackNot
2
不要使用@a,尽管答案中提供了别名建议,但这确实是您最好的选择。 - ysth
好的,我明白了提示!我甚至不会尝试去做这个,而是会使用@$aref。我的理由是我认为这会使代码更简单。 - Norman of Anstruther
1
@NormanofAnstruther:请记住,通常不需要引用整个数组。可以将单个元素称为$aref->[1]等。老式的方式是${$aref}[1](不好),或者$$aref[1](更糟糕)。另外要注意的是,在命令行或shebang行中使用-w相比于use warnings来说存在一些劣势。 - Borodin
显示剩余4条评论
4个回答

7

我想知道为什么你想这样做?我猜测这是一个性能问题,但通常的解决方案是通过引用传递数据。写$aref->[1]$a[1]一样容易。

你可以通过在包符号表中分配类型全局变量来给你的引用起别名,但别名必须是一个包变量。

use strict;
use warnings;

my $aref = [1, 2, 3];

our @a;
*a = $aref;

$a[1] = 99;

print "aref = @$aref\n";
print "a    = @a\n";

输出

aref = 1 99 3
a    = 1 99 3

有很多模块提供了漂亮的语法,并允许您为词法变量设置别名。

以下是使用Lexical::Alias的版本,它具有将词法变量设置别名的优点,并且比分配给类型环境更加健壮。 Data::Alias以非常相似的方式工作。输出与上述相同。

use strict;
use warnings;

use Lexical::Alias qw/ alias_r /;

my $aref = [1, 2, 3];

alias_r $aref, \my @a;

$a[1] = 99;

print "aref = @$aref\n";
print "a    = @a\n";

另一种方法是使用alias而不是alias_r与之配合使用

alias @$aref, my @a;

3
绝对避免在这个答案中使用第一个建议;当你不必使用非词汇变量时,没有好的理由使用它。 - ysth
@ysth:我认为“绝对避免”有点过了。包变量具有词法作用域,并不需要在任何地方都可见。如果必要的话,我不确定会选择一个模块而不是像 { our @a; *a = $aref; $a[1] = 99; say "@a"; } 这样的方式。此外,在子例程方面没有词法标识符的选择。 - Borodin
2
包变量具有词法作用域吗?这是错误的。词法别名 our 创建的是词法作用域,但数据仍然是全局的,具有可能带来混淆的所有潜在问题。Perl 5.18引入了(实验性的)词法子例程;这是人们长期以来想要的东西。 - ysth
@ysth:当然可以。但我更倾向于将责任归咎于完全限定的标识符,而不是包变量本身。我很少看到用其包名称限定的包变量,但我也很少看到它们被正确地作用域化。遗憾的是,这同样适用于词法变量。 - Borodin
你正在处理一个次要问题,而不是主要问题。{ our $a; $a .= "a" } { our $a; $a .= "b"; print $a } 输出的是“ab”,而不是“b”,就像 sub foo { our $a; $a = "ab" } { our $a; $a = "b"; foo(); print $a } 一样。全局变量即使没有完全限定的标识符也是一个问题,因为它们没有作用域。 - ysth
@ysth:我正在回应你的观点。你可以选择将其标记为旁注。而且你非常清楚全局变量是有作用域的——你甚至之前就这么说过,{our $a = 99} print $a证明了这一点。请尽量限制你的评论在有助于社区的主题上。偶尔使用our声明变量是必要的,只要考虑到作用域,它就不会引起任何麻烦,并且填补了Perl 5中的一个空缺。鼓励避免使用our和包变量是公平的,但你的绝对避免是愚蠢的。 - Borodin

6
  1. our @array; local *array = $aref;
    

    Pros: Built-in feature since 5.6.
    Cons: Ugly. Uses a global variable, so the variable is seen by called subs.

  2. use Data::Alias qw( alias );
    alias my @array = @$aref;
    

    Pros: Clean.
    Cons: This module gets broken by just about every Perl release (though it gets fixed quickly if not before the actual release).

  3. use feature qw( refaliasing );
    no warnings qw( experimental::refaliasing );
    \my @array = $aref;
    

    Pros: Built-in feature.
    Cons: Requires Perl 5.22+, and even then, the feature is experimental.


1

1

为了详细解释Borodin的回答,我已经使用Lexical::Alias模块进行了测试:

#!/usr/bin/perl -w

use strict;
use Lexical::Alias 'alias_a';

my $aref = [1, 2, 3];
my @a;
alias_a(@$aref, @a);
$a[1] = 99;
print "aref = @$aref\n";
print "a = @a\n";

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接