【问题标题】:Can I name an anonymous array in Perl?我可以在 Perl 中命名一个匿名数组吗?
【发布时间】:2015-08-07 23:26:49
【问题描述】:
#!/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 引用的数组?

【问题讨论】:

  • 只使用@$aref有什么问题?
  • 您可以将@a作为参考,my $a = $aref
  • @NormanofAnstruther 这就是我留下评论而不是答案的原因。如果你解释为什么你想要做某事而不是仅仅解释你想怎么做,你通常会得到更好的答案。
  • 它没有;他建议你不要使用@a。尽管答案中给出了别名建议,但这确实是您的最佳选择。
  • @NormanofAnstruther:请记住,您通常不想引用整个数组。单个元素可以称为$aref->[1] 等。老式的方式是${$aref}[1](坏)或$$aref[1](更糟)。另请注意,use warnings 在各方面都优于命令行或 shebang 行上的-w

标签: arrays perl


【解决方案1】:

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

您可以别名您在包符号表中的引用,方法是分配给 typeglob,但别名必须是包变量

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 的版本,它具有为词法变量别名的优势,并且可能比分配给 typeglob 更健壮。 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 with

alias @$aref, my @a;

【讨论】:

  • 绝对避免在这个答案中使用第一个建议;没有必要使用非词法变量。
  • @ysth:我觉得绝对避免有点强。包变量具有词法范围,不需要在任何地方都可见。如果有必要,我不确定是否会选择一个模块,比如{ our @a; *a = $aref; $a[1] = 99; say "@a"; }。此外,在子例程中没有词法标识符的选择
  • 包变量有词法范围?那是错误的。词法别名our 创建是词法的,但数据仍然是全局的,有可能带来破坏。 perl 5.18 引入了(实验性的)词法子;这是人们长期以来一直想要的东西。
  • @ysth:是的,当然。但我更愿意将责任归咎于完全限定的标识符,而不是包变量本身。我很少看到用它们的包名称限定的包变量,但我也很少看到它们的范围是正确的。可悲的是,这同样适用于词法变量
  • 您是在处理一个次要问题,而不是主要问题。 { 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 } 也是如此。全局变量即使没有完全限定的标识符也是一个问题,因为它们没有作用域
【解决方案2】:
  1. our @array; local *array = $aref;
    

    优点:自 5.6 以来的内置功能。
    缺点:丑陋。使用全局变量,因此被调用的 subs 可以看到该变量。

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

    优点:干净。
    缺点:几乎每个 Perl 版本都会破坏这个模块(尽管如果不是在实际发布之前它会很快得到修复)。

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

    优点:内置功能。
    缺点:需要 Perl 5.22+,即便如此,该功能也是实验性的。

【讨论】:

    【解决方案3】:

    为了扩展 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";
    

    【讨论】:

      【解决方案4】:

      一种选择是使用来自 CPAN 的 Data::Alias 包。

      这样你就可以写了:

      #!/usr/bin/perl
      
      use Data::Alias qw( alias );
      
      my $aref  = [1, 2, 3];
      
      alias my @a = @$aref;
      
      $a[1] = 99;
      print "aref = @$aref\n";
      print "a = @a\n";
      

      关于 SO 的相关问题可以在这里找到:Assign address of one array to another in Perl possible?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-09
        • 2022-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-27
        • 2012-10-25
        • 2023-03-25
        相关资源
        最近更新 更多