由于公司需要,本人最近在学习Perl这种脚本语言,本文是我在学习Perl的过程中总结出来的一些心得和笔记,希望能够帮助也在学习Perl的各位同僚。废话不多说直接上干货!!!
———————————————————————————干货分割线 —————————————————————————
引例:
数据拷贝:
$a = “stone”;
$b = $a;
此时,$b是$a的一个数据拷贝,即两个变量中的数据完全一致,但是当$a修改时,$b不变,仍然是stone.
数据引用:
$a = “stone”;
$b = \$a; (引用的写法,后面会介绍)
此时,$b是$a的一个数据引用,当$a修改时,$b也会跟着被修改.
引用的好处:1>节省内存开支.2>方便修改变量(当有多个变量同时引用一个变量的时候,只要修改被指向的元数据,引用就会被修改)
引用:它是指向一组数据的指针,并不包含实际数据的本身。该引用通常存放在另一个标量变量中。
大白话解释:我(相当于$b变量)指着你(相当于$a变量),你的位置,穿衣吃饭,胳膊腿都可以看做是变量中的数据(相当于$a中的stone).无论你从T恤换成了棉袄,从北京来到了上海,还是自残剁了条胳膊(你的数据发生了改变),但我始终指着你.其实我本身并没有数据,只是起到一个桥梁的作用,将你的数据,牵引到用到你的地方.
创建引用的方法:
$ref = \$a;
不能简单地对$ r e f进行操作,因为它里边没有通常的标量值。如果输出$ref,就会显示类似SCALAR (0X0000)的信息。若要通过$ref获得$ a中的值,必须间接引用$ref。间接引用可以被视为上面的方块图中按箭头方向的引用。
通过引用输出值:
print $$ref;
通过引用修改原始值:
$$ref = “sticks”;
若果你使用$ r e f而不是$ $ r e f:
$ref = “Break”;
那么存放在$ r e f中的引用将被撤消并被实际值取代.
给引用赋值:
$name = “mountain .king”;
$nref = \$name;
$oref = $nref;
得到的结果如下:
给引用赋值引用:
$book = “jinpingmei”;
$bref = \$book;
$bref2 = \$bref;
得到的结果如下:
如果使用$ b r e f 2来输出书名,那么该引用将是$$$b r e f 2,如果使用$ b r e f,则该引用是$ $ b r e f。
请注意,$ $ $ b r e f 2多了一个美元符号,它需要增加一层间接引用,才能获得原始值。
对数组的引用:
$aref = \@arr;
形式:
使用引用访问数组:
$$aref[0] #输出@arr的第一个元素
@$aref[2,3] #输出@arr的一个片,即同时输出$$aref[2],$$aref[3]的值
@$aref #输出整个数组
也可以这样表示:
${$aref}[0]
${$aref}[2,3]
@{$aref}
使用引用输出数组:
foreach $element(@{$aref}){
print $element;
}
对Hash的引用:
$href = \%hash;
形式:
使用引用访问Hash:
$$href{key} <===> ${$href}{key}访问%hash结构中的一个关键字
%$href <===> %{$href}访问整个hash结构
PS:<===>表示等同于,即该符号前后两种写法一致的意思
使用引用迭代输出所有值: 使用hash结构迭代输出所有值:
foreach $key(keys%$href){ foreach my $key(keys%hash){
print$$href{$key}; print$hash{$key};
} }
为了便于记忆和避免混淆,在此列出两种形式的对比,由此可知使用引用时只是比使用原hash多了一个紧挨的$符号。
引用的适用场合☞引用作为参数传递给子函数:
由于整个数组或哈希结构均可被引用,并且该引用可以存放在一个标量中,因此,借助这些引用,可以调用带有多个数组或哈希结构的函数。
Exp:
#不能正常执行
@fruit = qw(apples oranges banana);
@veggies = qw(carrot cabbage turnip);
getarrays(@fruit,@veggies);
sub getarrays{
my (@a,@b)= @_;
...
}
#可以正常执行
@fruit = qw(apples oranges banana);
@veggies = qw(carrot cabbage turnip);
getarrays(\@fruit,\@veggies); #引用
sub getarrays{
my ($friut_ref,$veg_ref)= @_; #引用
...
}
引用的适用场合☞在子函数中为全局变量赋值:
当我们调用一个公共脚本里的函数作为调用脚本的子函数时,往往会从子函数里获得一些参数赋值给父函数,这与平时我们将父函数中的参数传递给子函数供其使用的做法恰恰相反。如下例所示,全局变量的值$dir是通过子函数中的引用赋予的。
my $dir; #定义的全局变量
getdir(\$dir); #j将全局变量的引用赋值给子函数
print $dir; #输出:USER/ADMIN/DESKTOP
sub getdir{
my ($sourdir) = @_;
$$sourdir = "USER/ADMIN/DESKTOP"; #在子函数中为引用赋值
}
数据拷贝和数据引用的对比:
数据拷贝:
#!/usr/bin/perl
sub changehash{
my (%local_hash) = @_;
$local_hash{mammal} = 'bear';
return;
}
%hash = (fish => 'shark', bird => 'robin');
changehash (%hash);
foreach (keys %hash){
print "$hash{$_}\n";
}
PS:在本例中,@_取得% hash中每个关键字值对的各个值。在子例程changehash( )中,现在放入@_中的哈希结构的各个元素被拷贝到%
localhash中。%
localhash被修改.当子例程返回后,%localhash就被撤消,而程序的主要部分中的%hash则保持不变。
数据引用:
sub changehash{
my ($href) = @_;
$$href{mammal} = 'bear';
return;
}
%hash = (fish => 'shark', bird => 'robin');
changehash (\%hash);
foreach (keys %hash){
print "$hash{$_}\n";
}
PS:在本例中,对% h a s h的引用通过@_被传递到子例程c h a n g e h a s h ( )中。该引用被拷贝到$href中,它仍然指原始哈希% h a s h。在子例程中,$ h r e f指向的哈希结构被修改。c h a n g e h a s h ( )返回后,原始哈希结构% h a s h将包含新关键字b e a r.
关于引用的函数:
ref函数,若变量是引用则返回真,否则返回假。实际上它更智能,它会返回引用对应的类型,比如HASH或者ARRAY。
EXP:
my $book = "jinpingmei";
my $bkref = \$book;
if(ref $bkref){
print "是引用,类型为:ref $bkref\n";
}else{
print "不是引用";
}
输出:
判断多个引用是否指向同一目标:
想要达到该目的,可以使用eq或者==
my $book = "jinpingmei";
my $book2 = "xiyouji";
my $bkref1 = \$book;
my $bkref2 = \$book;
if($bkref1 == $bkref2){ #或者是eq,效果一样
print "指向同一目标\n";
}
创建各种结构:
在下面的代码段中,代码块中创建了一个哈希结构% h a s h,并且这个哈希结构是该代码块的专用结构:
my $href;
{
My %hash = (phone => ‘bell’,light => ‘Edision’);
$href = \%hash;
}
print $$href{light}; #输出Edision.
在这个代码块中,标量$ h r e f被赋予对% h a s h的引用。当该代码块存在时,即使% h a s h已经消失,$ h r e f中的引用仍然有效(因为% h a s h是代码块的专用结构)。当结构本身已经超出作用域之后,对该结构的引用仍然可以存在,$ h r e f引用的哈希结构仍然可以修改。
P e r l提供了一个机制,可以用来创建引用,而不必使用中间的哈希结构% h a s h。这个机制称为匿名存储。下面这个例子创建了一个对匿名哈希结构的引用,并把它存储在$ a h r e f中:
$ahref = {phone => ‘Bell’,light => ‘Edison’};
花括号{}将哈希结构括起来,返回对它的引用,实际上并没有创建新的变量。
也可以使用方括号( [ ])创建匿名数组:
$aaref = [qw(crosby stills nash young)];
P e r l并不支持真正的二维数组。P e r l允许你使用数组引用的数组,模仿建立二维数组.
创建数组的数组:
@list_of_lists = (
[qw(Mustang Bronco Ranger)],
[qw(Cavalier Suburban Buick)],
[qw(Lebaron Ram)]
);
要访问最里层的列表的各个元素(即二维数组中的单元格),可以使用下面这个代码:
$list_of_lists[0][1]; #访问Bronco
$list_of_lists[1][2]; #访问Buick
最外层的列表中的元素数目:
$#list_of_lists; #最外层元素的索引:2
scalar(@list_of_lists); #列表的行数:3
里层列表中的某个列表的元素数目:
scalar(@{$list_of_lists[2]}); #列表索引为2的元素个数为:2
$#{$list_of_lists[1]}; #列表索引为2的行元素的最后索引为:2(第三个元素)
遍历列表的列表中每个元素:
foreach my $outer(@list_of_lists){
foreach my $inner(@{$outer}){
print “$inner”;
}
print “\n”;
}
向列表中添加元素:
push(@list_of_lists,[qw(Mercedes BMW Lexus)]);
push(@{$list_of_lists[0]},qw(Taurus));
Exp:
#!/usr/bin/perl -w
use strict;
use warnings;
my @list_of_lists = (
[qw(Mustang Bronco Ranger)],
[qw(Cavalier Suburban Buick)],
[qw(Lebaron Ram)]
);
#向列表中添加元素
push(@list_of_lists,[qw(Mercedes BMW Lexus)]);
push(@{$list_of_lists[0]},qw(Taurus));
#遍历元素
foreach my $outer(@list_of_lists){
foreach my $inner(@{$outer}){
print "$inner ";
}
print "\n";
}
输出:
迷宫游戏:
该游戏结合本节的知识点.迷宫蓝图为:
Exp:
#!/usr/bin/perl -w
use strict;
use warnings;
#########################################################
#@maze定义迷宫的布局
#数组中的元素e,w,s,n分别表示方向东,西,南,北
#如第0行第1个元素swe:表示该位置可以向南,西,东三个方向移动
#-:表示此位置不可进入
#########################################################
my @maze = (
[qw(e swe we ws)],
[qw(ne new sw ns)],
[qw(ns - ns wn)],
[qw(ne w ne w)]
);
#定义移动方向
my %direction = (
n => [-1,0],
s => [1,0],
e => [0,1],
w => [0,-1]
);
my %full = (
e => 'East',
n => 'North',
w => 'West',
s => 'South'
);
#$curr_x,$curr_y:当前位置,设置为(0,0)坐标点
#$x,$y:目标位置,设置为(3,3)坐标点
my ($curr_x,$curr_y,$x,$y) = (0,0,3,3);
my $move;
sub disp_location{
my ($cx,$cy) = @_;
print "You may move ";
#若元素能匹配则根据简称输出全称
while($maze[$cx][$cy] =~ /([nsew])/g){
print "$full{$1}";
}
#输出简称
print "($maze[$cx][$cy])\n";
}
sub move_to{
#该函数取出一个方向(存入$new中),和当前位置的引用
my ($new,$xref,$yref) = @_;
#lc函数将变量改为小写字母,substr函数取出变量的第一个字母:East->e
$new = substr(lc($new),0,1);
#搜索当前房间方向索引,若不匹配则输出非法值
if($maze[$$xref][$$yref] !~ /$new/){
print "Invalid direction,$new.\n";
return;
}
#坐标被修改
$$xref += $direction{$new}[0];
$$yref += $direction{$new}[1];
}
until ($curr_x == $x and $curr_y == $y){
disp_location($curr_x,$curr_y);
print "Which way?";
#读入方向变量,若为q则退出
$move =<STDIN>; chomp $move;
exit if($move =~ /^q/);
move_to($move,\$curr_x,\$curr_y);
}
print "You made it through the maze!\n";
游戏步骤的可能输出: