Perl将引用分配给子例程

3
我在子程序中使用@_获取参数,该参数被分配为数组的引用,但结果并未显示为数组引用。
以下是我的代码。
my @aar = (9,8,7,6,5);

my $ref = \@aar;

AAR($ref);

sub AAR {
   my $ref = @_;
   print "ref = $ref";
}

这将打印出 1,而不是一个数组引用。但是如果我将 @_ 替换为 shift,则打印结果将是一个引用。

有人可以解释一下为什么我不能使用 @_ 获得一个引用吗?


1
https://dev59.com/aHI95IYBdhLWcg3w2Rzz - mob
2个回答

8

这是关于Perl中上下文的内容。它是这门语言的重要方面。

像下面这样的表达式

my $var = @ary;

尝试将数组分配给标量。这没有意义,右侧被计算为数组元素的数量,并将其分配给$var。为了更改此行为,您需要向赋值运算符提供“列表上下文”。在这种情况下,您可以这样做:
my ($var) = @ary;

现在我们有一个列表(数组元素的列表)分配给另一个列表(变量列表,这里只有$var),它们一一对应地被分配。因此,在这里,@ary的第一个元素被分配给$var。请注意,该语句与“列表”这一难以捉摸的概念相对松散。
所以在你的情况下,你想要:
my ($ref) = @_;

并且从@_中获取第一个元素并将其分配给$ref,如有需要。

或者,您可以使用shift删除并返回@_的第一个元素,在这种情况下,标量上下文分配是可以的。

my $ref = shift @_;

在这种情况下,您也可以这样做。
my $ref = shift;

shift 默认情况下对 @_ 起作用。

当您想要移除输入的第一个元素并将其分配时,这非常有用,因此剩余的 @_ 很适合进一步处理。这通常在面向对象的代码中完成。


值得指出的是,Perl 中许多运算符和内置设施在调用上下文不同时会有不同的行为。举几个具体例子:正则表达式匹配运算符在标量上下文中返回 true/false(1/空字符串),而在列表上下文中返回实际匹配项;readdir 在标量上下文中返回单个条目,但在列表上下文中返回所有条目;而 localtime 则显示了更明显的差异。这种上下文敏感的行为贯穿于 Perl 的各个角落。通过 wantarray,用户级子例程也可以被制作成这种方式。

请参阅标量 vs 列表赋值运算符进行详细讨论。

例如,请参阅perlretutperlop


2
谢谢您的解释。您的答案让我更好地了解了Perl语法。 - Henry Lu
@HenryLu 欢迎。我建议你先阅读 perldata(第一个链接),然后在 perldoc 上寻找其他资源。还可以参考 learn.perl.org - zdim
一个可能有帮助的补充是:创建列表的不是(),而是当它们处于列表上下文中时,如1,2,31..5@foo都是列表(例如,子例程的参数或foreach迭代的列表)。这只是一种特殊情况:在赋值左侧加上括号会将其转换为列表赋值。在赋值右侧的列表周围经常需要加上括号以保证优先级。更多信息请参见:http://altreus.blogspot.com/2011/08/lists-and-things-made-of-lists.html - Grinnz
@Grinnz 对于OP来说应该会很有帮助,然后我想补充一下,“列表”这个概念本身就是有点难以捉摸的(但这并不是我在这里要讨论的)。此外,由于LHS ()将列表上下文强加到=操作符上,因此RHS列表被复制到LHS _list_中(嗯,在“List”变量中)。因此,我们通过 () 得到一个列表——非常宽泛(和不太准确)地说。再次强调,语法无法创建“列表”(它在堆栈中,术语与给定上下文中运算符的工作方式相关),但这会涉及到一些棘手的语义问题 :) - zdim

2
当你将一个数组赋给一个标量时,你得到的是数组的大小。你向 AAR 传递了一个参数(一个对数组的引用),这就是为什么你得到了1。
要获取实际参数,请将本地变量放在大括号中:
sub AAR {
   my ($ref) = @_;
   print "ref = $ref\n";
}

这将打印类似于ref = ARRAY(0x5566c89a4710)的内容。

然后,您可以使用引用来访问数组元素,如下所示:

print join(", ", @{$ref});

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