如何在不先使用 @ 的情况下在取消引用的数组上使用 #?



perl 中的数组是这样取消引用的,

my @array = @{$array_reference};

当尝试将数组分配给不带"@"的取消引用时,例如,

my @array = {$array_reference};

Perl 抛出错误,"匿名哈希中的元素数量为奇数,位于 ./sand.pl 行 22。我们不能将它分配给数组变量 becauase Perl 对类型感到困惑。

那么我们该如何执行...

my $lastindex = $#{$array_reference};

如果 Perl 难以理解 '{$array_reference}' 是一种数组类型?如果这看起来像这样,对我来说更有意义,

my $lastindex = $#@{$array_reference};

(尽管看起来丑陋得多)。

tl;dr:匹配$#array的语法是$#{$array_reference}


{}有很多含义,这就是Perl。

有时{}会创建一个匿名哈希。这就是{$array_reference}正在做的事情,试图制作一个哈希,其中键是$array_reference的字符串化,类似于"ARRAY(0x7fb21e803280)",没有价值。因为您尝试创建具有键但没有值的哈希,所以您会收到"奇数个元素"警告。

有时{...}是一个块,如sub { ... }if(...) { ... },或do {...}等等。

有时它是一个像{ local $/; ... }这样的光秃秃的块.

有时它表示哈希的键,如$hash{key}$hash->{key}.

前面有某些符号{}使取消引用变得明确。虽然你可以写$#$array_reference@$array_reference但有时你想取消引用一些不是简单标量的东西。例如,如果你有一个返回数组引用的函数,你可以用$#{ get_array_reference() }在一行中获取它的大小。匹配$#array的语法是$#{$array_reference}

$#{...}取消引用数组并获取索引。@{...}取消引用数组。%{...}取消引用哈希。${...}取消引用标量。*{...}取消引用一个球体。

你可能会发现 Modern Perl 中的变量名和符号部分有助于更好地了解模式。

如果这看起来像...

这样的事情很多。Perl 自 1987 年以来一直存在。很多这样的设计决策都是几十年前做出的。用于确定{}含义的代码特别复杂。数组和数组引用之间存在区别有点奇怪。

$array[$index]
@array[@indexes]
@array
$#array

相当于

${ @array }[$index]
@{ @array }[@indexes]
@{ @array }
$#{ @array }

看到模式了吗?无论在何处使用数组的NAME,都可以改用返回对数组的引用的BLOCK。这意味着您可以使用

${ $ref }[$index]
@{ $ref }[@indexes]
@{ $ref }
$#{ $ref }

这在 Perl Dereferencing Syntax 中得到了说明。


请注意,如果BLOCK只包含一个简单的标量,则可以省略卷曲。

$$ref[$index]
@$ref[@indexes]
@$ref
$#$ref

还有一个"箭头"语法被认为更清晰。

$ref->[$index]
$ref->@[@indexes]
$ref->@*
$ref->$#*

Perl 对类型感到困惑

Perl 很难理解 '{$array_reference}' 是一个数组类型

好吧,它不是数组类型。Perl 不会"挣扎";你只是有错误的期望。

一般规则(如perldoc perlreftut中所述)是:您始终可以使用大括号中的引用来代替变量名。

因此:

@array           # a whole array
@{ $array_ref }  # same thing with a reference
$array[$i]           # an array element
${ $array_ref }[$i]  # same thing with a reference
$#array           # last index of an array
$#{ $array_ref }  # same thing with a reference

另一方面,这是怎么回事

my @array = {$array_reference};

是您正在使用哈希引用构造函数的语法,{ LIST }.出现警告是因为相关列表应该具有偶数个元素(对于键和值):

my $hash_ref = {
key1 => 'value1',
key2 => 'value2',
};

您写的内容被视为

my @array = ({
$array_reference => undef,
});

即包含单个元素的数组,它是对包含单个键的哈希的引用,这是一个字符串化引用(其值为undef)。

取消引用和哈希引用构造函数之间的语法区别在于,取消引用以符号(如$@%)开头,而哈希引用构造函数仅以裸{开头。


从技术上讲,取消引用语法中的{}形成了一个实际的代码块:

print ${
print "onen";  # yeah, I just put a statement in the middle of an expression
print "twon";
["three"]  # the last expression in this block is implicitly returned
# (and dereferenced by the surrounding $ [0] construct outside)
}[0], "n";

出于(希望)显而易见的原因,没有人真正在实际代码中这样做。

语法是

my $lastindex = $#$array_reference;

它分配给$lastindex匿名数组最后一个元素的索引,该元素引用在变量$array_reference中。

代码

my @ary = { $ra };  # works but you get a warning

不会抛出"错误",而是发出警告。换句话说,您确实会得到一个元素的@ary,即对匿名哈希的引用。但是,哈希需要具有偶数个元素,因此您还会收到警告,指出事实并非如此。

您最后一次尝试使用@{$array_reference}取消引用数组 -- 这将返回一个列表,而不是数组变量。 "列表"是内存中稍纵即逝的标量集合(想想在堆栈上复制标量去其他地方);这样的事情没有"索引"的概念。因此,$#@{$ra}甚至没有按预期解析,并且是语法错误。

语法$#ary只适用于变量@ary,然后是$#$arrayref语法。您通常可以编写$#{$arrayref}因为卷曲允许计算结果为数组引用的任意表达式,但没有理由这样做,因为您确实有一个带有数组引用的变量。

我很乐意同意,这种语法的大部分需要一些习惯,这样说。

最新更新