12

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

$x = $myarray[1];
$y = $myhash{'foo'};

而不仅仅是做:

$x = myarray[1];
$y = myhash{'foo'};

为什么上面有歧义?

如果在那个地方不是 $ 的话,那不是非法的 Perl 代码吗?例如,在 Perl 中,以下所有内容不都是非法的吗?

@var[0];
@var{'key'};
%var[0];
%var{'key'};
4

9 回答 9

22

我刚用过

my $x = myarray[1];

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

$ perl foo.pl 
Flying Butt Monkeys!

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

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

use strict;
use warnings;

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

my $x = myarray[1];

因此 myarray 调用一个子例程,将一个对包含单个元素 1 的匿名数组的引用传递给它。

这是您需要阵列访问上的印记的另一个原因。

于 2008-09-30T16:43:53.217 回答
18

切片并不违法:

@slice = @myarray[1, 2, 5];
@slice = @myhash{qw/foo bar baz/};

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

于 2008-09-30T15:55:35.063 回答
11

印记为您提供容器的返回类型。因此,如果某些内容以 开头@,您就知道它会返回一个列表。如果它以 开头$,则返回一个标量。

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

# 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

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

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

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

于 2008-09-30T16:01:44.533 回答
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 的切片部分。

于 2008-09-30T15:59:41.183 回答
9

人们已经指出,你可以有切片和上下文,但是符号是用来将变量的东西与其他东西分开的。您不必知道所有的关键字或子程序名称来选择一个合理的变量名称。这是我怀念其他语言中 Perl 的一大优点。

于 2008-09-30T17:24:20.933 回答
7

我可以想到一种方法

$x = myarray[1];

是模棱两可的——如果你想要一个名为 m 的数组怎么办?

$x = m[1];

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

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

于 2008-09-30T15:50:28.897 回答
6

在 Perl 5(将在 Perl 6 中更改)中,符号指示表达式的上下文

  • 你想从哈希中得到一个特定的标量,所以它是$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 > 作为完整的表达式。

于 2008-09-30T17:09:20.377 回答
4

印记为访问提供了上下文:

  • $表示标量上下文(标量变量或散列或数组的单个元素)
  • @表示列表上下文(整个数组或散列或数组的一部分)
  • %是一个完整的哈希
于 2008-09-30T16:21:44.470 回答
4

在 Perl 5 中,您需要符号($ 和 @),因为裸字标识符的默认解释是子例程调用的解释(因此在大多数情况下无需使用 & )。

于 2008-09-30T18:50:25.237 回答