【问题标题】:How can I pass a reference of an array defined as constant?如何传递定义为常量的数组的引用?
【发布时间】:2022-08-04 14:00:18
【问题描述】:

我定义了哈希和数组常量,当将它们传递给函数时,我必须将它们作为引用传递。 但是我想知道正确的语法是什么。

考虑这个例子:

#!/usr/bin/perl
use strict;
use warnings;

use constant AC => qw(a b c);

sub f($)
{
    print \"ref=\", ref $_[0], \"\\n\";
    print \"$_\\n\" foreach (@{$_[0]});
}

f(\\AC);

当我运行它时,我得到:

ref=SCALAR
Use of uninitialized value $_ in concatenation (.) or string at /run/media/whatever/constref.pl line 10.

Perl 调试器将AC 打印为一个数组:

13: f(\\AC);
  DB<1> x AC
0  \'a\'
1  \'b\'
2  \'c\'
  DB<2> c
  • @Dave Cross 对不起,你是对的。我搞砸了我的测试。

标签: perl constants


【解决方案1】:

constant pragma 文档中的 List Constants 部分告诉我们

常量可以是多于(或少于)一个值的列表。
...
列表常量是列表,而不是数组。

这意味着,除其他属性外,一个不能引用该“列表常量”,就好像它是单个实体一样,就像数组变量一样;它表现为一个列表,一组标量。

为了完成所要求的,我们需要从该列表中构建一个(匿名)数组引用并传递它,f([AC])

use warnings;
use strict;
use feature 'say';

use constant AC => qw(a b c);

sub f {
    my ($r) = @_;
    say "ref=", ref $r;
    say for @$r;
}

f( [ AC ] );

这会将“列表常量”作为单个值、数组引用传递,并按预期打印。但是,我不喜欢复制值,也不喜欢进一步失去任何恒定性的表象。还有其他方法可以做到这一点,但这些方法对我来说更不受欢迎。§

我建议在需要适当的只读变量时重新考虑使用该工具。

还有其他库,我推荐Const::FastReadonly

use Const::Fast;    
const my @const_ary => qw(a b c);
f( \@const_ary );                 # same f() from above

use Readonly;
Readonly my @carr => qw(a b c);
f( \@carr );                      # same f() from above

这些是可以像处理任何其他变量一样处理的词法变量。请参阅文档。


尝试正式“引用”列表会导致引用列表

\($v, $t)  -->  \$v, \$t

虽然AC 本身是一个常量,但它与isn't read-only 关联的列表

use constant AC => qw(a b c);

(AC)[1] = "other";

say for AC;

印刷

a
other
c

他们只是不是恒定的。


§我可以看到另外两种方式

  • constant pragma produces (is implemented as) a subroutine。然后一个可以使用它并照原样传递它,f(\&amp;AC),然后照原样使用它,say for $r-&gt;()

    但是,现在我们必须从该列表符号 (AC) 传递和取消引用一个子例程,并获取一个列表。这是一个非常糟糕的黑客攻击。

  • 问题中的代码使用“常量列表”。可以改用引用,并且可以这样传递

    use constant AC => [ qw(a b c) ];
    
    # same sub f { } as above
    
    f( AC );  # prints as expected
    

    但是,我不知道如何取消引用AC 以获取整个列表(@{ AC } 不去?),除了先将它复制到 arrayref,就像在f() 中一样。但这违背了将其作为constant 的目的——并且所有pretense to constant-ness 都被删除了。

【讨论】:

  • 上 ”列表常量是列表,而不是数组“:所以两者都是有序的、索引的和有限的(这使它们成为我的“数组”),但区别似乎是(在 C 语言中)列表不是“左值”,并且引用需要一个左值。但是我'已经看到像my $r = \1; 这样的代码。在列表上尝试似乎将其评估为标量,并提供对标量的引用(这是列表项的数量)。很棘手,不是吗?
  • 一个很好的答案!由于我的操作系统没有附带Const::Fast,所以我不想添加另一个依赖项。不幸的是,我的操作系统在 Perl 5.18.2 中也缺少对 Readonly 的描述,尽管它在 man 3pm constant 的“SEE ALSO”中有所提及。我猜这是操作系统(SlES12 SP5)中的错误。
  • 我发现我必须在 SLES12 SP5 中安装一个单独的包 (perl-Readonly)。我之前的猜测是,如果可用,它会包含在核心包中。
  • @U.Windl 嘿,是的,这很棘手。这里的问题是,列表不是变量。它实际上是一个标量列表(在堆栈上),相当难以捉摸和短暂。所以“参考”的并没有真正的意义——人们会得到一个列表,其中包含每个参考。 (通常不是一个意思:)。但是是的,可以做\1 等。明天我会寻找一些(许多)讨论 list-vs-array 的帖子(现在已经很晚了),这很有趣。
  • @U.Windl 它们的行为通常相似,并且表达式中的数组通常(在内部)通常首先评估为列表,然后再进行操作。但是行为上有很多差异,因为它们是非常不同的事物。你提出的案例就是一个很好的例子。对于我的@ary = (2,3,4); my $r = \@ary;$r 是对变量(数组)的引用。但是对于我的$r = \(2,3,4);,这是这样的:引用运算符 \ 通过 () (还有什么?),并且由于 = 运算符在标量上下文中,逗号运算符一个接一个地进行评估(与 \ 作用于每个)...和$r 得到\4
猜你喜欢
  • 1970-01-01
  • 2017-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-18
  • 1970-01-01
相关资源
最近更新 更多