为什么在访问Perl中的数组和哈希元素时需要$?

Lor*_*ein 11 arrays perl hash sigils

由于数组和散列只能包含Perl中的标量,为什么在访问数组或散列元素时必须使用$来告诉解释器该值是标量?换句话说,假设您有一个数组@myarray和一个哈希%myhash,为什么需要这样做:

$x = $myarray[1];
$y = $myhash{'foo'};
Run Code Online (Sandbox Code Playgroud)

而不只是做:

$x = myarray[1];
$y = myhash{'foo'};
Run Code Online (Sandbox Code Playgroud)

为什么上面的含糊不清?

如果除了那个地方的$之外,它不是非法的Perl代码吗?例如,Perl中的以下都不是非法的吗?

@var[0];
@var{'key'};
%var[0];
%var{'key'};
Run Code Online (Sandbox Code Playgroud)

hex*_*ten 22

我刚刚用过

my $x = myarray[1];
Run Code Online (Sandbox Code Playgroud)

在一个程序中,令我惊讶的是,这是我运行时发生的事情:

$ perl foo.pl 
Flying Butt Monkeys!
Run Code Online (Sandbox Code Playgroud)

那是因为整个程序看起来像这样:

$ cat foo.pl 
#!/usr/bin/env perl

use strict;
use warnings;

sub myarray {
  print "Flying Butt Monkeys!\n";
}

my $x = myarray[1];
Run Code Online (Sandbox Code Playgroud)

所以myarray调用一个子例程,将它传递给包含单个元素1的匿名数组.

这是你需要在阵列访问上使用sigil的另一个原因.


zig*_*don 17

切片不是非法的:

@slice = @myarray[1, 2, 5];
@slice = @myhash{qw/foo bar baz/};
Run Code Online (Sandbox Code Playgroud)

我怀疑这是你需要指定是否要从哈希/数组中获取单个值的部分原因.


mor*_*itz 11

sigil为您提供容器的返回类型.因此,如果有东西开始@,你知道它返回一个列表.如果以它开头$,则返回标量.

现在,如果在sigil之后只有一个标识符($foo或者@foo,那么它是一个简单的变量访问.如果它后跟一个[,它是对数组的访问,如果它后跟一个{,则它是对哈希的访问.

# variables
$foo
@foo

# accesses
$stuff{blubb} # accesses %stuff, returns a scalar
@stuff{@list} # accesses %stuff, returns an array
$stuff[blubb] # accesses @stuff, returns a scalar
              # (and calls the blubb() function)
@stuff[blubb] # accesses @stuff, returns an array
Run Code Online (Sandbox Code Playgroud)

一些人类语言具有非常相似的概念.

然而,许多程序员发现令人困惑,因此Perl 6使用了一个不变的sigil.

一般来说,Perl 5编译器想要在编译时知道某些内容是在列表中还是在标量上下文中,因此如果没有前导符号,则某些术语会变得模棱两可.


noh*_*hat 9

这是有效的Perl : @var[0]. 它是长度为1的数组切片.@var[0,1]将是一个长度为2的数组切片.

@var['key']是无效的Perl,因为数组只能用数字索引,而其他两个(%var[0] and %var['key'])不是有效的Perl,因为散列片使用{}来索引散列.

@var{'key'}并且@var{0}都是有效的哈希切片.显然,采用长度为1的切片是不正常的,但它肯定是有效的.

有关在Perl中进行切片的更多信息,请参阅perldata perldoc的切片部分.


bri*_*foy 9

人们已经指出你可以有切片和上下文,但是可以将变量与其他东西分开.您不必知道所有关键字或子例程名称来选择合理的变量名称.这是我在其他语言中想念Perl的重大事项之一.


Pau*_*xon 7

我可以想到一种方式

$x = myarray[1];
Run Code Online (Sandbox Code Playgroud)

是不明确的 - 如果你想要一个名为m的数组怎么办?

$x = m[1];
Run Code Online (Sandbox Code Playgroud)

除了正则表达式匹配之外,你怎么能说出来呢?

换句话说,语法是帮助Perl解释器,好吧,解释!


Axe*_*man 6

在Perl 5中(要在Perl 6中进行更改),sigil表示表达式的上下文.

  • 你想要一个哈希的特定标量,所以它是$hash{key}.
  • 你想要一个特定插槽的值超出一个数组,所以它是$array[0].

然而,正如zigdon指出的那样,切片是合法的.他们在列表上下文中解释这些表达式.

  • 您需要哈希@hash{key}工作中的1个值的列表
  • 但是更大的列表也可以使用@hash{qw<key1 key2 ... key_n>}.

  • 你想要一个阵列中的几个插槽@array[0,3,5..7,$n..$n+5]工作

  • @array[0] 是一个大小为1的列表.

没有"哈希上下文",所以既没有%hash{@keys}也没有%hash{key}意义.

所以你有"@"+ "array[0]"<=> <sigil = context> + <indexing expression>作为完整的表达式.