当前位置: 首页 > Web后端 > Perl > 正文

Perl基础总结

2018-04-23 来源:博客园/hi_fly

一、数据类型(Data Type)

学习一门编程语言,首先需要了解的就是这门编程语言有那几种数据类型。Perl的数据类型大致可以分为四类:Scalar(标量)、Array(数组)、Hash(哈稀)以及Reference(引用)。看起来,四种数据类型似乎显得先天不足,但用起来却已绰绰有余。

1、Scalar(标量)

标量是Perl中最简单的一种数据类型,也是构成其它三个数据类型的基石。标量变量可以代表一个字符、字符串以及数字(整数或浮点数)。变量变量以$开头。如下:

1 my $x = "abcd";
2 my $y = 999999;
3 my $z = 1.0001;

在Perl中,字符串型标量和数值型标量并没有显著的差别。实际上,在特定情况下,Perl会根据需要在字符串和数值之间进行转换。是否发生转化由操作符决定,若操作符需要的是一个字符串而提供的操作数却是一个数值,或者反过来,操作符需要的是数值而提供的操作数却是字符串,那么转化将发生。
对数值进行运算的操作符(比如加减乘除运算)如果遇到字符串类型的操作数,Perl会自动将字符串转化成等效的十进制浮点数进行运算。比如,12 * "f10d"会得到0,而12 * "10fd"却会得到120。
同样的,对字符串进行操作的操作符遇到数值型的操作数时,给数值就被转换成相同的字符串。比如"xyz" . 99会得到"xyz99"。

2、Array(数组)和List(列表)

列表可以看成是由一系列标量的有序集合,而数组就是用来存储列表的变量,数组变量以@开头。如下:

1 my @arr = (17, "hello", 13.78);
2 my @arr = (length("hello"), "xy" . "z");
3 my @arr = ($var, 0.09*55);

等号左边是列表,右边是数组变量,数组中存储着列表。当然,列表不止这一种表示方式。需要注意的有两点:
(1)Perl中数组变量创建时初始值为空列表()
(2)Perl中数组变量和标量标量处于不同的命名空间,所以同一个变量名可以同时用作数组变量和标量变量而不用担心命名冲突。
数组中元素可以通过下标操作符[]表示,第一个元素的下标为0,最后一个元素的下标为-1。试图访问不存在的数组元素将得到undef,如果给超出数组大小之外的元素赋值,则Perl数组将自动增长,原来没有的元素的值为undef。如下:

my @arr = (1, 2, 3);
my $var = $arr[5];  # $var will get undef
$arr[5] = 8;      # @arr changes to (1,2,3,undef,undef,8)

需要注意的是,当你需要提取某个数组元素时,用的是$开头,而非@,这很容易理解:数组的元素是一个标量值。

3、Hash(哈稀)和散列

哈稀是一种数据结构,它和数组的区别在于:不像数组以下标来检索元素,哈稀使用键来检索元素。可以这样理解:哈稀结构中每一个元素都有一个键和一个值,键必须唯一,可以通过键来映射到值。如下所示:

my %hash = (1 => "fred", 2.5 => 1, "fred" => 2.5);

其中,符号"=>"在Perl中被戏称为胖箭头,它很好的展示了哈稀结构中键与值的映射关系:胖箭头左边的1、2.5以及"fred"是键,胖箭头右边的"fred"、1、2.5就是各个键对应的值。任何的标量元素都可以作为hash结构中的键和值,上面的哈稀结构三对键值对就形成了一个循环。
关于胖箭头,需要补充的一点是,在Perl中胖箭头"=>"与逗号","是完全等价的,因此上面右边的散列中的胖箭头完全可以用逗号代替。使用胖箭头的唯一理由就是它清晰的表达了各个键与值映射关系。

4、引用(reference)和地址

应该说引用使得Perl中数组和哈稀变得更键灵活而强大。引用表达的是一种“指向”的关系,因此它类似于C语言中的指针。比如你创建一个引用让它指向一个数组:

my $ref1 = \@arr;
my $ref2->[0] = "first";
$ref2->[2] = 3;

这两种方法都会创建一个引用,第一种方法要求数组@arr被已经申明。第二种方法到更像是创建了一个类似于数组的怪物,之所以说它是怪物是因为你如果需要访问数组的某个元素,你只能使用箭头符号"->"来完成下标的指定,类似于:

my $var = $ref->[num];

这里num显然是一个整数值。一般来说,引用的创建多用来指向到一个数组或者一个哈稀。创建一个引用指向一个标量似乎没有太大的必要。
有了引用,我们就可以使用标量、数组以及哈稀来任意地构造我们自己的数据结构,比如:

my $arr_double->[0] = \(1, 2, 3);
$arr_double->[1] = \(4, 5, 6);
$arr_double->[2] = \(7, 8, 9);

这样的二维数组你应该不会感到陌生和意外。那么“二维”哈稀呢?

my $hash_double->{'line1'}->{'row1'} = "first";
$hash_double->{'line1'}->{'row2'} = "second";

需要说明的是根本没有“二维”哈稀这样诡异的说法,它只是笔者的玩笑而已,当然如果你一定要把它戏称为“二维”哈稀的话,那么也就你自己心里想想就好,千万别在某个重要的会议上说出来。

二、运算符及其优先级

Perl下的运算符来基本上借鉴于两种语言:C与Pascal。全部的运算符及其结合性如下:

表2-1  Perl中操作符
操作符  结合性  完成的操作
()  左  改变运算的优先级;列表操作符
->  左  引用操作符
++ --  左  ++自增,--自减 
**  右  乘幂
\ ! ~ + -  右  都是单目操作符,\取地址,!逻辑非,~按位非,+正号,-负号
=~ !~  左  =~匹配绑定操作符,!~不匹配绑定操作符(这东西太诡异了)
* / % x  左  *乘,/除,%求余,x字符串重复操作符
<< >>  左  移位操作符
-X -r rand shift
 
 左  具名的单目操作符,-X与-r都是文件测试操作符,rand得到一个随机值
< <= > >= lt le gt ge  左  “不等”关系运算符,前四个比较数值,后四个比较字符串
== != <=> eq ne cmp  左  “相等”关系操作符,前三个比较数值,后三个比较字符串
&  左  按位与
| ^  左  |按位或,^按位异或
&&  左  逻辑与
||  左  逻辑或
.. ...  左  ..范围操作符,
?:  右  Perl中最诡异的操作符:三目(条件)操作符
= += x= .=  右  赋值以及增量赋值操作符
, =>  左  逗号操作符;列表操作符(右结合性)
not  右  逻辑非
and  左  逻辑与
or xor  左  or逻辑或,xor逻辑异或

如你所见,Perl中操作符很多很多,而且有很多冗余的,比如逻辑操作符有两套,and/not/or/xor系之所以存在,是因为它们的优先级很低,这 样使用它们有时你可以省敲一些括号。全部记住这些操作符及其优先级和更加让人头疼的结合性显然是不现实的,并且也有悖于Perl程序懒惰的作风,所以合理 的使用圆括号是值得推荐的,也很有必要。
各个操作符具体的操作方法请参考任意一本讲解Perl的书,当然我要推荐大骆驼书。

三、关于context(上下文)

上下文是一种很重要的概念,尽管我们未必留意到它,但是我们却无时无刻不在使用它。比如,某次考试后,你问别人“嘿,第21题怎么回事?”,你的同学应该可以立刻直到你在问什么。但如果你把这句话同样的说给刚刚睡醒爷爷听,他一定会感到莫名其妙。这就是上下文的概念。
在Perl中,上下文就是概念就是:同一个表达式,出现在不同的地方会有不同的结果和意义。
我们直到Perl中最最常见的就是标量和列表了,这形成了Perl中两种最常见上下文环境:标量上下文和列表上下文。标量上下文中的表达式被期望返回一个标量值,而列表上下文中的表达式则被期望返回一个列表。比如:

4 * something
shift something
keys something

这里,something出现在三个地方:乘号操作符期望它是一个数值,因此第一个something处于标量上下文,更准确点是数值上下文;shift操作符期望它是一个列表,因此第二个something就处于列表上下文;最后keys函数期望something是一个散列(哈稀结构),所以最后一个something就处于散列上下文。
需要补充说明的是,散列也是一种列表,只是散列的元素个数为偶数个,且索引为偶数的元素要求在该散列中独一无二、各不相同而已。所以最常见的上下文还是标量上下文和列表上下文。

1、在标量上下文中使用产生列表的表达式

这个情况没有统一的规定,但是,大多数情况下会返回列表元素的个数,这基本上就是你期望的。尽管如此,我还是打算详细说明一些比较“特殊”的。
某些表达式不会在标量上下文中返回任何值。比如,sort在标量上下文中返回的是undef。有人或许会认为应该返回列表元素的个数,可是谁会通过对列表排序来获得列表的个数呢?
某些表达式在标量上下文中会返回列表所有元素连接而成的串。比如reverse,在标量上下文中,它会返回逆序后的字符串(先将列表中所有元素串连在一起,在对结果进行反序处理)。
另外需要强调的是,对于print操作符,其后是一个列表上下文。

2、在列表上下文中使用产生标量的表达式

这种情况十分简单:它会自动产生一个仅含此标量值的列表,即使这个标量值为undef。需要注意的是空列表和仅含一个元素且其值为undef的列表是两个不同的概念。如下:

my @arr = undef;
my @arr = ();

前者的元素个数是1,二后者是名副其实的空列表,它的元素个数为0。

四、语句结构

1、判断条件和“布尔”值

Perl中没有专用的布尔类型的值,关系运算的结果也会是一个标量值,Perl中任何标量值都可以作为控制结构的判断条件。Perl中判定一个标量为真还是假的规则很简单:
(1)如果值为数值,0为假,所有其它数值为真;
(2)如果值为字符串,空字符串(""或'')为假,所有其它字符串为真;
(3)如果不是数值也不适字符串,那么就先转化成数值或字符串再进行判断,所以undef为假,所有的引用都为真;
需要注意的一点就是:字符串'0'或"0"跟数字0是同一个标量值,所以也为假,这是非空字符串为假的唯一的例外。
对于列表,现将它转化成标量值在进行判断(也就是说控制结构的判断条件是一个标量上下文)。

2、条件控制结构

if控制结构如下:

if (condition1) {
    something;
} elsif (condition2) {
     something;
} else {
    something;
}

注意,Perl中控制结构的花括号不是可有可无的,而是必须存在的。Perl中暂时没有switch结构,在Perl6中或许会有这个结构。其它分支选择结构还有unless结构,只是比较少用。

3、循环控制结构

while循环控制结构如下:

while (condition) {
    something;
}

foreach循环控制结构如下:

foreach $var (@arr) {
    something;
}

for循环结构如下:

for (initialization;condition;increment) {
    something;
}

需要注意的是,Perl并不区分for和foreach这两个关键词,也就是说,对于Perl解释器foreach与for表达同样的含义,因此不管是for还是foreach都可以引领这两种循环结构。其它循环结构还有until结构,但是用的比较少。

4、函数

函数以关键词sub申明,一个函数结构如下:

sub function_name {
    something;
}

调用函数的方法如下:

&function_name(parameter_list);

对于函数,需要注意的是在调用时,函数的参数是一个列表上下文,所以才叫做参数列表嘛。传给函数的参数被放在函数的下划线变量@_中。Perl中函数的返回值可以通过return语句显示返回,如果没有return语句,则返回最后一个条语句的执行结果。