常见变量类型
标量
数组
散列(哈希、字典)
引用 (reference)
创建引用
使用引用 (Using References)

看了一遍 perl 基础资料,很多 Perl 代码还是似懂非懂。无怪乎那些"乱七八糟 "的上下文形式,"莫名其妙"的符号,"神乎其神"的正则表达式。

其实这背后却是简单的,不过需要了解好基础。本文详解 Perl 中的变量,变量 是计算机程序语言的基础!

注意:这里不咬文嚼字了,变量是一个代词,可以是标量、数组、哈希(关联数 组)、引用、子程序、类型团。

常见变量类型

Perl 就下面这些变量(就我目前所知,:-)

类型 字符 例子 用于哪种名字
标量 $ $cents 一个独立的数值(数字或字串)
数组 @ @large 一列数值,用编号做键字
散列 % %interest 一组数值,用字串做键字
子过程 & &how 一段可以调用的 Perl 代码
类型团 * *struck 所有叫 struck 的东西

当你看到 "$I_am_not_a_scalar_variable" ,它一定是个标量变量!其他同理

标量

在 Perl 中标量可以赋予:整数,浮点数,字符串,甚至指向其他变量或对象的引用 这样深奥的东西。

由于 Perl 的设计者们认为要让 Perl 更像人类语言 ,所以 Perl 中出现了重要 的上下文含义。记住一点,引用数组,散列(哈希、字典)中的“值”时,因为它 们都是“标量”,所以要用 "$" 符号。

$number = 1024;             # 一个数字变量(Perl 中所有数字都是以浮点类型存储的)
$string = "Hello world!";   # 一个字符串变量
$string = \@a_array;        # 一个引用 (后面讲解)

从现在开始,变量标识符前有 "$" 符号的都当作标量处理。("\$" 当作引用处理!)

数组

数组(array)是一个 list ,成员都是标量(引用也是标量)

@linuxs = ("debian", "redhat", "ylinux");  # 经典的数组赋值/创建,却是不常用的 :-)
@linuxs = qw# debian redhat ylinux#;       # 这种常用,# 可以是 / { () 等等

注意,数组里面的标量可以是引用,后面讲解。

散列(哈希、字典)

哈希(也称散列、关联数组),Python 中对应概念是字典。提供一个无序的列 表,可以通过标量做索引。同数组是一个有序列表,使用自然数做索引有同有异。

%longday = ("Sun", "Sunday",
            "Mon", "Monday",
            "Tue", "Tuesday",
            "Wed", "Wednesday",
            "Thu", "Thursday",
            "Fri", "Friday",
            "Sat", "Saturday");

这样赋值更准确:

%longday = ("Sun" => "Sunday",
            "Mon" => "Monday",
            "Tue" => "Tuesday",
            "Wed" => "Wednesday",
            "Thu" => "Thursday",
            "Fri" => "Friday",
            "Sat" => "Saturday",);

因为散列是一种特殊的数组,你可以通过 {} 来获取单个的散列元素.比如,如果你 想找出与关键字 Wed 对应的值,你应该使用 $longday{"Wed"}.注意因为你在处理 标量,因此你在 longday 前面使用 $,而不是 %,% 代表整个散列.

引用 (reference)

参考

  1. Perl doc 之 perlref -- 引用的手册
  2. Perl doc 之 perlreftut 的中文翻译 Perl doc 之 perlreftut

Perl 除了上面列举的直观数据结构,还可以组织非常复杂数据结构。这一切建立 在一个叫“引用”(reference)的概念上。(如果知道 C ,这和指针没有什么区 别)

引用是一个标量!

创建引用

使用 "\"

将 "\" 符号放在变量前可以创建指向这个变量的引用

$scalarref = \$foo;
$arrayref = \@ARGV;
$hashref = \%ENV;
$coderef = \&handler;
$globref = \*foo;

"[]" 和 "{}" 创建匿名引用

$arrayref = [1, 2, ['a', 'b', 'c']];

现在 $arrayref->[2][1] 可以得到 'b'

还可以这样创建:

@list = (\$a, \@b, \%c);
@list = \($a, @b, %c);      # 同上!

使用 "{}" 可以创建匿名哈希引用:

$hashref = {'Adam' => 'Eve',
            'Clyde' => 'Bonnie',};

因为 "{}" 也有表示一个子过程含义,所以在有歧义的时候要变通一下。下面在 hashem 函数结尾想返回一个 hash 引用,需要加上 "+" 或 "return" 才正确!

sub hashem { { @_ } } # silently wrong
sub hashem { +{ @_ } } # ok
sub hashem { return { @_ } } # ok

如果你真的要表示另外的意思

sub showem { { @_ } }        # 有歧义! (currently ok, but may change)
sub showem { {; @_ } }       # ok
sub showem { { return @_ } } # ok

"+{" 和 "{" 可以消除歧义,表示一个引用,BLOCK(子过程)

子过程的引用

$coderef = sub { print "Boink!\n" };

下面一个示例,&$h("world") 等于 {my $y = shift; print "Howdy, $y!\n";}("world")

sub newprint {
  my $x = shift;
  return sub { my $y = shift; print "$x, $y!\n"; };
}
$h = newprint("Howdy");
$g = newprint("Greetings");

# Time passes...

&$h("world");
&$g("earthlings");

输出:

Howdy, world!
Greetings, earthlings!

类型团中

$scalarref = *foo{SCALAR};
$arrayref = *ARGV{ARRAY};
$hashref = *ENV{HASH};
$coderef = *handler{CODE};
$ioref = *STDIN{IO};
$globref = *foo{GLOB};
$formatref = *foo{FORMAT};

使用引用 (Using References)

一般使用

任何时候将引用标识符(包括$符号)放到语句中 ,都是使用这个引用:

$bar = $$scalarref;
push(@$arrayref, $filename);
$$arrayref[0] = "January";
$$hashref{"KEY"} = "VALUE";
&$coderef(1,2,3);
print $globref "output\n";

较好的写法是用 "{}" 包围引用变量,上面的写法还可以这样:

$bar = ${$scalarref};
push(@{$arrayref}, $filename);
${$arrayref}[0] = "January";
${$hashref}{"KEY"} = "VALUE";
&{$coderef}(1,2,3);
$globref->print("output\n"); # iff IO::Handle is loaded

再一个多层引用:

$refrefref = \\\"howdy";    # 3层
print $$$$refrefref;        # 3个$,并1个$指名3层引用对象实体为标量

几种 HASH 引用写法示例:

$$hashref{"KEY"} = "VALUE";     # CASE 0
${$hashref}{"KEY"} = "VALUE";   # CASE 1
${$hashref{"KEY"}} = "VALUE";   # CASE 2
${$hashref->{"KEY"}} = "VALUE"; # CASE 3
$arrayref->[0] = "January";     # Array element
$hashref->{"KEY"} = "VALUE";    # Hash element
$coderef->(1,2,3);              # Subroutine call

更复杂点,array 是一个数组,第 x 个元素是个 hash 引用,hash 引用的 "foo" 值是一个数组引用,该数组引用的第 0 个元素是 "January" 字符串标量:

$array[$x]->{"foo"}->[0] = "January";

可以用简单脚本验证:

$ perl -e '$x=2;$array[$x]->{"foo"}->[0] = "January"; print $array[$x],"\n";'
HASH(0x9f849e0)
$ perl -e '$x=2;$array[$x]->{"foo"}->[0] = "January"; print $array[$x]->{"foo"},"\n";'
ARRAY(0x8a624b0)
$ perl -e '$x=2;$array[$x]->{"foo"}->[0] = "January"; print $array[$x]->{"foo"}->[0],"\n";'
January

更方便的写法:

$array[$x]{"foo"}[0] = "January";

和 C 里的多位数组有点像了:

$ perl -e '$score[3][4][5]=6;print $score[3],"\n";'
ARRAY(0x933a9e0)
$ perl -e '$score[3][4][5]=6;print $score[3][4],"\n";'
ARRAY(0x84d7490)
$ perl -e '$score[3][4][5]=6;print $score[3][4][5],"\n";'
6