Perl:为什么在访问数组中的特定元素时可以使用@或$?

时间:2018-12-11 20:37:18

标签: perl

我是Perl的新手,无法找到满意的答案

my @foo = ("foo","bar")
print "@foo[0]"
foo
print "$foo[1]"
bar

不仅@foo[0]可以正常工作,而且$foo[1]也可以输出字符串。

为什么?即使启用了use strict

3 个答案:

答案 0 :(得分:7)

@foo[0]$foo[1]都是合法的Perl构造。

$foo[$n],或更常见的是$foo[EXPR]是一个标量元素,代表数组$n的第@foo个元素(索引从0开始)(或任何EXPR得出的结果)。

@foo[LIST]是一个数组切片@foo中的元素集由LIST中的索引指示。当LIST具有一个元素,例如@foo[0]时,则@foo[LIST]是具有一个元素的列表。

尽管@foo[1]是一个有效的表达方式,但经验表明,通常更不恰当地使用构造,而更适合说$foo[1]。因此,在启用警告并使用该构造时会发出警告-而不是错误。

$foo[LIST]在Perl中也是有效的表达式。只是Perl会在标量上下文中评估LIST并返回与该评估相对应的@foo元素,而不是元素列表。

@foo = ("foo","bar","baz");
$foo[0]     returns the scalar "foo"
@foo[1]     returns the list ("bar") (and issues warning)
@foo[0,2]   returns the list ("foo","baz")
$foo[0,2]   returns "baz"   ($foo[0,2] evaluates to $foo[2], and issues warning)
$foo[@foo]  returns undef   (evaluates to $foo[scalar @foo] => $foo[3])

转移:我想出的使用@foo[SCALAR]的唯一原因是作为左值,可以区分标量/列表上下文。考虑

sub bar { wantarray ? (42,19) : 101 }

$foo[0] = bar();会将值101分配给@foo的第一个元素,但是@foo[0] = bar()会分配值42。但是,除非您打高尔夫球,否则即使您说($foo[0]) = bar()也无法做到这一点。

答案 1 :(得分:7)

Perl信号告诉您如何处理数据,并且仅与变量类型松散相关。不用考虑是什么,而是考虑它正在做什么。这是Perl中名词的动词:

  • $使用单个项目
  • @使用多个项目
  • %使用对

标量变量$foo是单个项目,并使用$符号。由于没有单个项目的倍数或成对,因此其他信号不再起作用。

数组变量@foo可能包含许多项目,@一起引用了所有这些项目。 $foo[INDEX]引用数组中的单个项目,并使用$标记。您可以使用数组切片引用多个项目,例如@foo[INDEX,INDEX2,...],并为此使用@。您的问题集中在一个元素@foo[INDEX]的切片的简并情况下。可以,但是在列表上下文中。有时,行为会有所不同。

哈希变量%foo是键值对的集合。要获取单个值,请再次使用$,例如$foo{KEY}。您还可以使用@通过散列切片获得多个值,因为它是多个值,例如@hash{KEY1,KEY2,...}

而且,这是最近的发展:Perl 5.20 introduces “Key/Value Slices”。您可以获取数组或哈希的哈希切片。 %array[INDEX1,INDEX2]%hash{KEY1,KEY2}。这些返回键值对列表。在数组的情况下,键是索引。

对于具有单个元素访问权限或切片类型的数组和哈希,您可以通过索引字符来了解变量类型:数组使用[],而哈希使用{}。而且,还有另一个有趣的问题:这些分隔符根据单个或(可能)多个项目提供标量或列表上下文。

答案 2 :(得分:2)

@foo[0]$foo[1]都是合法的Perl构造。

$foo[EXPR](其中EXPR是在标量上下文中求值的任意表达式)返回由表达式结果指定的单个元素。

@foo[LIST](其中LIST是在列表上下文中求值的任意表达式)返回表达式结果指定的每个元素。

(与其他文章相反,Perl中没有$foo[LIST]这样的东西。使用$foo[...]时,表达式总是在标量上下文中求值。)

尽管@foo[1]是一个有效的表达方式,但经验表明,通常更不恰当地使用构造,而更适合说$foo[1]。因此,当启用警告并使用该构造时,会发出警告(而不是例外)。

这意味着什么:

my @foo = ( "foo", "bar", "baz" );

$foo[0]        0 eval'ed in scalar cx.  Returns scalar "foo".             ok
@foo[1]        1 eval'ed in list cx.    Returns scalar "bar".             Weird. Warns.
@foo[0,2]    0,2 eval'ed in list cx.    Returns scalars "foo" and "baz".  ok
$foo[0,2]    0,2 eval'ed in scalar cx.  Returns scalar "baz".             Wrong. Warns.
$foo[@foo]  @foo eval'ed in scalar cx.  Returns undef.                    Probably wrong.

我想使用@foo[SCALAR]的唯一原因是作为区分标量/列表上下文的某个地方的左值。考虑

sub bar { wantarray ? (42,19) : 101 }

$foo[0] = bar();会将值101分配给@foo的第一个元素,但是@foo[0] = bar();会分配值42。改为使用($foo[0]) = bar()更为常见。


mob版权所有的部分帖子,与本网站相同。

这篇文章解决了暴民post中的许多问题,包括1)滥用LIST意味着在列表上下文中使用任意表达式以外的东西; 2)假装parens创建列表,3)假装返回标量和返回列表之间存在差异,并且4)假装没有非致命错误之类的东西。