文档章节

perl读书笔记

hunterli
 hunterli
发布于 2012/06/25 21:34
字数 8174
阅读 136
收藏 1
点赞 0
评论 0

1.在Perl 内部没有整数值,程序中的整数被当做等价的浮点数来处理。
2.Perl 允许用下划线来分隔整数,如:61298040283768==61_298_040_283_768;适用于非十进制数字表示中的整数部分,如16进制:0x5065727C==0x50_65_72_7C。
3.八进制以0 开头,十六进制以0x 开头,二进制0b 开头。
4.“前置0”指示符只对数字有效,对由字符串转换过来得数字无效。
5.10.5%3.2会转换为10%3后再计算。
6.**是指数操作符,如2**3,表示2 的3 次方,等于8。
7.最短的字符串不含任何字符。最长的字符串,可以填满整个内存。
在perl语言中,几个特殊而常用的符号:
q  是单引号
qq 是双引号
qw 单词列表引号
qr 正则表达式引号
qx 反引号
其中qq,qw又较为常用。
qq{foobar}的意思为意思为双引号字符串,可内插变量,相当于 "foobar"
qw{foo bar}的意思为用空格分解字符串,得到列表,相当于如下语句
split(' ','foo bar') 得到的结果是'foo','bar'
q 和 qq 运算符的特点:
q 和 qq 必须是一个标识符,而不是标识符的部分。例如:
q (abc)      用 () 作为分界符
q(abc)       用 () 作为分界符
q xabcx      用 x 作为分界符
都是合法的,
而qxabcx 就会被当作是一个标识符来处理,有谁会想到 qxabcx 居然是一个 q 运算式呢?
q 和 qq 后面的空格并不会影响语法,但是任何非空字符(不是空格、不是 TAB 字符、不是换行符)则会被当作界限符来使用。
如果 q 和 qq 使用一些特殊的符号的时候,
则必须配对。比如:< 只能和 >; 在一起用来当作界限符,而不能只用两个 < 作为界限符。
而 | 则只能和它自己作为一对界限符。这些特殊的符号有:()、{}、[]、<>;
8.Perl 中NULL字符没有特殊的含义。Perl 能计算长度,不用靠null 来判断字符串是否结束。
9.单引号字符串中,除了单引号和反斜线之外的任何字符都表示它自身。只有在反斜线(\)后面接的是\或单引号’,其才会被当作特殊符号来处理。
10.字符串重复操作符(string repetition operator),由小写的字母x 表示,能把操作符左边字符串重复操作符右边数字那么多次。复制次数(右操作数)在使用之前会把它转换为小于等于它的整数(如,4.8 变为4)。重复次数小于1 将产生空串(长度为0)。
11.操作符(如+)需要数字,Perl 将把操作数当作数字看待。如果操作符需要字符串(如. ),Perl 将把操作数当作字符串看待。
12.若操作符(如+)需要数字,而给出的是个字符串,则字符串后面的非数字部分和前面的空格将被去掉;在极端情形,当一个不含任何数字的字符串将别转换为0。
13.当程序中包含可能的错误时,可以要求Perl 警告你。运行程序时,可以在命令行中使用–w 这个参数把警告打开,如下:
$ perl–w my_program
或者:
#! /usr/bin/perl –w
14.Perl5.6 或之后的版本中,可以使用pragma 来打开警告(warning),如:
#! /usr/bin/perl
use warnings;
15.在字符串中变量前($符号前)加上反斜线(\),变量将不会被内插(替换)。
16.在双引号字符串中,可以用花括号将变量名括起来,以便于区分,如:
print “fred ate $n $whats.\n”; #是使用变量$whats的值
print “fred ate $n ${what}s.\n”; #是使用变量$what的值
17.if-else分支中,花括号是必须的(这一点和C 不同)。
18.Perl没有Boolean 类型。perl的真假判断规则:
*如果值为数字,0 是false;其余为真
*如果值为字符串,则空串(‘’)为false;其余为真
*如果值的类型既不是数字又不是字符串,则将其转换为数字或字符串后再利用上述规则
*undef为false,所有的引用都是true。
*字符串‘0’是唯一一个非空但值为0 的串。
19.如果字符串结尾有换行符,chomp可以去掉它。如:
chomp($text); #去掉换行符(\n)。
@lines = <STDIN>; #读入所有的行
chomp = (@lines); #去掉所有的换行符
或:
chomp (@lines = <STDIN>); #读入所有的行,不包括换行符
20.可以使用defined 函数判断变量值,为undef 时返回false,其余返回true。
21. 当数组变量出现在预期简单变量出现的地方,则PERL解释器取其长度。
@array = (1, 2, 3);
$scalar = @array; #$scalar=3,即@array的长度
($scalar) = @array; # $scalar=1,即@array第一个元素的值
注:以数组的长度为循环次数可如下编程:
$count = 1;
while ($count <= @array) {
  print ("element $count: $array[$count-1]\n");
  $count++;
}
22.(5..1)#空列表—..中的左值应小于右值,否则为空。
23.$end = $#rocks; #数组最后一个元素的索引
$number_of_rocks = $end + 1;#数组长度
24.数组的负数索引值从最后一个元素开始。
25.以下数组形式是等价的:
(“fred”, “barney”, “betty”, “wilma”, “dino”)
qw(fred barney betty wilma dino )
qw ! fred barney betty wilma dino !
qw# fred barney betty wilma dino # #有些像注释
qw( fred barney betty wilma dino )
qw{ fred barney betty wilma dino }
qw[ fred barney betty wilma dino ]
qw< fred barney betty wilma dino >
qw(fred
barney betty
wilma dino)
26.数组名前加@(后没有中括号)来引用整个数组。$用于引用单个数组元素。
27.perl中数组只能包含标量值。
28.@copy = @quarry; #将一个数组中的值拷贝的另一个数组中,即改变一个数组的元素不会影响另一个数组。
29.
@array = 5..9;
$fred = pop(@array); #$fred 得到9,@array 现在为(5,6,7,8)
$barney = pop @array; #$barney gets 8, @array 现在为(5,6,7)
pop @array; #@array 现在为(5,6)(7 被丢弃了)
如果数组为空,那pop 什么也不做(因为没有元素可以移出),并返回undef。
30.
push(@array,0); #@array 现在为(5,6,0)
push @array,8; #@array 现在为(5,6,0,8)
push @array,1..10; #@array 现在多了10 个元素
@others =qw/9 0 2 1 0 /;
push @array,@others; #@array 现在又多了5 个元素(共有19 个)
31.
@array = qw# dino fred barney #;
$m = shift (@array); #$m 得到“dino”, @array 现在为(“fred”, “barney”)
$n = shift @array; #$n 得到”fred”, @array 现在为(“barney”)
shift @array; #@array 现在为空
$o = shift @array; #$o 得到undef, @arry 仍为空
unshift(@array,5); #@array 现在为(5)
unshift @array,4; #@array 现在为(4,5)
@others = 1..3;
unshift @array, @others; #array 现在为(1,2,3,4,5)
32.数组也可以插入双引号的字符串中,插入的数组元素会自动由空格分开。
需要注意字符串中的邮件地址:
$email =“fred@bedrock.edu”; #错误!将会替换@bedrock
$email =“fred\@bedrock.edu”; #正确
$email =‘fred@bedrock.edu’; #另一种方法
33.Perl 最常用的默认变量:$_,如:
foreach(1..10){ #使用默认的变量$_
print “I can count to $_!\n”;
}
34.reverse(逆转)操作将输入的一串列表(可能是数组)按相反的顺序返回。
@fred = 6 ..10;
@barney = reverse (@fred); #得到10,9,8,7,6
@wilma = reverse 6 ..10; #同上,没有使用额外的数组
@fred = reverse @fred; #将逆转过的字符串存回去
注意reverse 返回逆转的列表,它不会改变其参数的值。如果返回值没有赋值给某个变量,那这个操作是没有什么意义的:
reverse @fred; #错误,没有改变@fred 的值
@fred = reverse @fred; #改变了@fred 的值
35.sort:
@rocks = qw/ bedrock slate rubble granite /;
@sorted = sort(@rocks); #得到bedrock, granite, rubble, slate
@back = reverse sort @rocks; #为slate 到bedrock
@rocks = sort @rocks; #将排序的值写回@rocks
@numbers = sort 97 ..102; #得到100,101,102,97,98,99
注意,同reverse一样,sort 返回逆转的列表,它不会改变其参数的值。
sort @rocks; #错误,不会修改@rocks
@rocks = sort @rocks; #现在@rocks 值是经过排序的
36.Perl 中的表达式将根据其context 返回适当的值,如:
@people = qw( fred barney betty );
@sorted = sort @people; #列表context:barney , betty, fred
$number = 42 + @people; #标量context:42+3,得到45
@list = @people; #3 个People 的列表
$n = @people ; #数字3
37.
一些表达式根本没有标量context 的值。例如,sort 在标量context 中返回什么?你不需要要排序一个列表来得到其个数,因
此,除非有人按另一种方式实现了sort,否则其在标量context 中返回undef。
另一个例子是reverse。在列表context 中,它返回反转的列表。在标量context 中,返回反转的字符串(或者将反转的结果串
成一个字符串):
@backwards = reverse qw / yabba dabba doo /;
#返回doo, dabba, yabba
$backwards = reverse qw/ yabba dabba doo /;
#返回oodabbadabbay
38.
其用法是显然的:如果一个表达式不是列表值,则标量值自动转换为一个元素的列表:
@fred = 6*7;
@barney = “hello”. ‘’. “world”;
下面是另一个例子:
@wilma = undef; #OOPS!得到一个元素的列表(undef),不同于下面的例子
@betty = (); #将数组置空的正确方法
39.Perl 子程序可以带参数,Perl 会自动将此参数列表(此参数列表的另一个名字)存放在一个叫做@_的数组中。@_是子程序的一个私有变量。
40.如果没有使用括号,my 仅定义一个变量。如:
my $fred, $barney; #错误!没有定义$barney
my ($fred, $barney); #两个均定义了
41.use strict; #迫使perl编译时采用更严格的检测。
42.许多人推荐如果程序长度大于一个屏幕,则需要使用use strict。
43.标量并非子程序返回的唯一类型。如果你在列表context 中调用某个子程序,则其会返回列表值。
44.读文件简写:
foreach(<STDIN>){#列表上下文,一次性读入,内存消耗大
print “I saw $_”;
}
while (defined($_ = <STDIN>)){#标量上下文,按行读入,内存消耗小
print “I saw $_”;
}
45.命令行中的-代表标准输入,如调用命令为"$ ./my_program fred – betty",其含义是程序将首先处理文件fred,其次是标准输入流,最后是文件betty。
46.尖括号操作(<>)是一种特殊的行输入操作。从一个文件到另一个文件之间没有空行,当使用<>时,就像输入的是一个大文件一样。如果输入结束时,<>将返回undef(同时退出while 循环)。如:
#$ ./my_program fred barney betty
while(<>){
chomp;
print “It was $_ that I saw!\n”;
}
47.<>从数组@ARGV 中得到调用参数。这个数组是Perl 中的一个特殊数组,其包含命令行参数的列表。程序开始运行时,调用参数已被存在@ARGV 之中了。
<>操作查看@argv 来决定使用哪些文件。如果表为空,则使用标准输入流;
在启动程序后,使用<>之前,可以手动修改@argv 的值,在用户没有输入必要参数时以作默认处理。
48.IO流,<或空表示只读,>写,>>追加。>会首先清空文件。
49.open打开文件时,成功返回真,打开失败返回假。
50.当结束一个文件句柄时,可以使用close关闭,关闭文件句柄将清空缓存,并释放文件的锁。如:
close BEDROCK;
51.$!包含对系统请求失败时的异常信息。如下:
if(!open LOG, “>>logfile”){
die “Cannot create logfile:$!”;
}
52.程序的名字在Perl 的特殊变量$0。
53.die 函数可以指定某个严重错误,warn 函数来产生警告信息。
54.默认情况下,如果不指定文件句柄给print(或者printf,这里的内容对两者均适用),则默认会使用STDOUT。可以通过select 操作进行更改:
select BEDROCK;
print “I hope Mr. Slate doesn’t find out about this.\n”;
print “Wilma!\n”
$| = 1;#将变量$|设置为1,将会在输出操作结束时会立刻清空文件句柄。
select STDOUT;#将默认文件句柄恢复为STDOUT。
55.
#将出错信息送到私有错误日志上
if(! Open STDERR, “>>/home/barney/.error_log”){
die “Can’t open error log for append: $!”;
}
56.当在名字前面是美元符号($),后面是花括号({}),则其为hash 元素。
57.使用%引用整个哈希表;和数组一样,使用$引用单个变量。
58.hash 反转:
%inverse_hash = reverse %any_hash;#value 和key 的位置交换了。
59.构造哈希表:
my %last_name = (
“fred” => “flintstone”,
“dino” => undef,
“barney”=> “rubble”,
“betty”=> “rubble”
);
60.
keys 函数会返回此hash 的所有keys,values 函数将返回所有的values。如果hash 中没有元素,则此函数将返回空列表:
my %hash = (“a”=>1, “b”=>2, “c”=>3);
my @k = keys %hash;
my@v = values %hash;
61.使用each遍历hash表:
while (($key, $value) = each %hash){
print “$key => $value\n”;
}
62.使用foreach遍历hash:
foreach $key (sort keys %hash){
$value =$hass{$key};
print “$key => $value\n”;
#print “$key => $hash{key}\n”;
}
63.使用exists 函数查看hash 中是否存在某个key。
if(exists $books{$dino}){
print “Hey, there’s a libaray card for dino!\n”;
}
64.delete 函数将某个给定的key(包括其对应的value)从hash 中删除。
my $person = “betty”;
delete $books{$person}; #将$person 的借书卡删除掉
65.模式匹配中,匹配变量$n代表模式中第n对括号所匹配的字符串。匹配变量的值会保持不变,直到下一个模式成功匹配为止
$_ = “Hello there, neighbor”;
if(/\s(\w+),/){ #空格和逗号之间的词
print “the word was $1\n”; #the word was there
}
66.自动匹配变量:$&, $`, $'
$&为整个被匹配的部分,匹配部分的前一部分存放在$`之中,后一部分被存到$'。三个变量连在一起得到原始字符串。
67.绑定操作符=~,将右边的模式在左边的字符串上进行匹配。
68.use strict 'vars';以后,所有的变量在使用前必须先被定义。
69.使用system或exec函数时,最好使用参数列表的形式调用,以免被注入危险代码。如下:
system "/bin/echo", $message;
70.perl汇报错误的特殊变量:
$! : 从操作系统或库函数调用得到的错误。
$? : 最近一次调用wait()得到的返回值。
$@ : 最近一次调用eval()得到的错误。
$^E : 操作系统特有的错误信息。
80.caller()函数可以返回当前的调用栈,如:
run();
sub run {
    print caller();#输出:main/home/ubuntu/workspace/perl/test.pl3
}
81.[]用于取数组的引用(见下面95),{}用于取哈希的引用,如:
#数组引用:
$arr = ['a', 'b'];
print $arr->[0];#a
#哈希引用:
$hash = {
    'a'=>'aaa',
    'b'=>'bbb'
};
print $hash->{'a'};#aaa
82.使用*取符号表,如下:
$foo = "fdfdf";
whoami(*foo);
sub whoami {
local $glob = shift;
print *{$glob}{PACKAGE}, ":", *{$glob}{NAME};#main:foo;
}
83.使用grep过滤列表:
my @results = grep EXPR, @input_list;
my $count   = grep EXPR, @input_list;
如:
my @input_numbers = (1, 2, 4, 8, 16, 32, 64);
my @bigger_than_10 = grep $_ > 10, @input_numbers;
84.使用map对列表进行转换:
my @input_numbers = (1, 2, 4, 8, 16, 32, 64);
my @result = map $_ + 100, @input_numbers;
85.使用eval包裹可能出异常的代码块,$@变量记录可能的异常信息:
eval { $average = $total / $count } ;#<--注意分号
print "Continuing after error: $@" if $@;
86.eval是一个函数,因此可以有返回值,带代码块抛出异常时,返回值为undef,否则返回最后一个表达式的值:
my $average = eval { $total / $count } ;
87.可以使用eval来执行动态代码,执行过程中发生的异常记录在$@变量中:
eval '$sum = 2 + 2';
print "The sum is $sum\n";
warn $@ if $@;
88.使用use命令引入模块,后面数组可限定引入的具体函数。
use File::Basename qw( fileparse basename );
#即使模块内只有一个函数,最好也写上qw(fileparse),以便统一。
#对于未显式引入的函数,可以使用全限定名引用(类似于java):
my $dirname = File::Basename::dirname($some_path);
#不带限定的use代表引入默认的函数列表(!注意不是全部,默认列表由模块的作者指定)
use File::Basename;
#带空列表的use代表不引入任何函数:
use File::Basename ();#no import
my $base = File::Basename::basename($some_path);
#对于面向对象的模块,无需使用限定列表
use File::Spec;
my $filespec = File::Spec->catfile( $homedir{gilligan}, 'web_docs', 'photos', 'USS_Minnow.gif' );
89.PERL5LIB环境变量设定的目录会被加到perl的模块搜索目录列表:
$ export PERL5LIB=/Users/home/Ginger
90.安装perl模块:
$ perl Makefile.PL PREFIX=/Users/home/Ginger
#或
$ perl Build.PL --install_base /Users/home/Ginger
#然后:
make
make test
make install
91.INC数组指定了模块搜索路径,use命令会参照此数组来搜索导入模块;
use命令是在编译期执行,因此,运行期动态改变此数组并不能影响use操作,如下:
unshift @INC, '/home/gilligan/lib';#broken,because 'unshift' happens at runtime
use Navigation::SeatOfPants;
#可以使用BEGIN代码块来修改@INC数组,因为BEGIN代码在编译期执行
BEGIN { unshift @INC, '/home/gilligan/lib'; }
use Navigation::SeatOfPants;
#或者使用lib pragma,同样在在编译期执行
use lib '/home/gilligan/lib';
use Navigation::SeatOfPants;
#注意,use lib指定的是搜索目录,而不是具体的模块文件,因此下面的写法是错误的:
use lib '/home/gilligan/lib/Navigation/SeatOfPants.pm'; # WRONG
#编译期只会对变量进行声明,而不会赋值,因此下面的写法也是错误的
my $LIB_DIR = '/home/gilligan/lib';
use lib $LIB_DIR;     # BROKEN
use Navigation::SeatOfPants;
#可以使用use constant在编译期声明一个常量来解决上面的问题:
use constant LIB_DIR => '/home/gilligan/lib';
use lib LIB_DIR;
use Navigation::SeatOfPants;
#综上,BEGIN代码和use lib都会改变代码,而且跨平台时写死的路径也可能引起问题,
#建议尽量使用PERL5LIB环境变量或perl -I参数来解决自定义搜索路径的问题
92.\是取引用操作符
my $reference_to_skipper = \@skipper;
my $aa = shift @$reference_to_skipper;#取出数组中的第一个元素
my $bb = shift @{$reference_to_skipper};#取出数组中的第一个元素
#两种往函数中传递数组的方式:
check_required_items('skipper', \@skipper);#传递指针
check_required_items('skipper', @skipper);#拷贝数组
#下面三者代表同一个值,数组里的第二个元素:
$skipper[1]
${$reference_to_skipper}[1]
$$reference_to_skipper[1]
#也可以使用->来解引(dereference),如下:
$reference_to_skipper->[1]
#可以合并连续的->操作符
my $root = \@all_with_names;
$root -> [2] -> [1] -> [0]
$root -> [2][1][0]
#注意,只有位于方括号或花括号(hash的情况)之间->操作符才能省略,即(if the arrow ends up between "subscripty kinds of things,"
#such as square brackets, we can also drop the arrow. )
#观察下面两组写法:
$root->[2]->[1]->[0]
$root->[2][1][0]#注意不是$root[2][1][0]
#
$all_with_names[2]->[1]->[0]
$all_with_names[2][1][0]
93.对hash取引用:
my %gilligan_info = (
  name => 'Gilligan'
);
my $hash_ref = \%gilligan_info;
my $name = $ gilligan_info { 'name' };
my $name = $ { $hash_ref } { 'name' };
my $name = $$hash_ref  { 'name' };
my $name = $hash_ref -> { 'name' };
#由hash引用转回
my @keys = keys %$hash_ref;
#->操作符省略的规则同样适用于hash引用,下面两者是等同的
$crew[0]->{'name'}
$crew[0]{'name'}
94.perl使用引用计数(reference counting)来跟踪对象的引用变化。
#只有引用计数降为0时,perl才会回收对象的内存
#对于回收的内存,perl通常不会返还给操作系统
#循环引用会破坏引用计数
#下面也会创建引用,函数退出时,该引用的随之失效,引用计数减一。
check_provisions_list(\@skipper)
#可以将引用赋值为undef或其他值来取消引用
$reference_to_skipper = undef;
#块内部定义的引用,块退出时随之失效
my @skipper = ...;
{ # naked block
my $ref = \@skipper;
...
} # $ref goes out of scope at this point
95.使用[]创建匿名数组的引用
my $ref_to_skipper_provisions = [ qw(blue_shirt hat jacket preserver sunscreen) ];
$aa = $ref_to_skipper_provisions->[1];#hat
#上面等同于
my $ref_to_skipper_provisions;
{
  my @temporary_name =
  ( qw(blue_shirt hat jacket preserver sunscreen) );#使用匿名数组构建新数组,匿名数组中的所有元素填充到新数组中。
  $ref_to_skipper_provisions = \@temporary_name;
}
#另一种常用的写法
my @skipper_with_name = (
  'The Skipper',
  [ qw(blue_shirt hat jacket preserver sunscreen) ]
);
#下面三种写法是等价的
my $fruits = [qw('pineapple', 'papaya', 'mango')];
my $fruits = ['pineapple', 'papaya', 'mango'];
my $fruits;
{
  my @secret_variable = ('pineapple', 'papaya', 'mango');
  $fruits = \@secret_variable;
}
#再来个复杂点的,返回一个大小为3的数组,每个数组元素是一个大小为2的数组(记为A)的引用,
#A的第二个元素又是一个数组的引用。
sub get_provisions_list {
  return (
    ['The Skipper',   [qw(blue_shirt hat jacket preserver sunscreen)] ],
    ['The Professor', [qw(sunscreen water_bottle slide_rule radio)  ] ],
    ['Gilligan',      [qw(red_shirt hat lucky_socks water_bottle)   ] ],
  );
}
#还有
['Mrs. Howell',
  [  ]#空数组的匿名引用
],
96.不要犯迷糊
#构建大小为2的数组,第二个数组元素是一个引用,指向另一个数组
my @skipper_with_name = (
  'The Skipper',
  [ qw(blue_shirt hat jacket preserver sunscreen) ]
);
#构建大小为6的数组
my @skipper_with_name = (
  'The Skipper',
  qw(blue_shirt hat jacket preserver sunscreen)
);
97.使用{}创建匿名hash的引用
my $ref_to_gilligan_info = {
  name     => 'Gilligan',
  hat      => 'White',
  shirt    => 'Red',
  position => 'First Mate',
};
my @crew = (
  {
    name     => 'Gilligan',
    hat      => 'White',
    shirt    => 'Red',
    position => 'First Mate',
  },
  {
    name     => 'Skipper',
    hat      => 'Black',
    shirt    => 'Blue',
    position => 'Captain',
  },#这个逗号是特意留的,美其名曰便于维护
);
#代码块和匿名hash都使用{},因此可能会使perl解析器判断错误,
#此时,在{}前加个加号,则明确的告诉解析器这是一个匿名hash;
#在{}内开始处加个分号,则明确的告诉解析器这是一个代码块;
#如下:
 +{ ... }#匿名hash
 {; ... }#代码块
98.autovivification
任何一个不存在的或者是值为undef的变量,当被解引(dereference)以便从中寻找
一个位置(学术上被称为“左值上下文”)来存储某项内容时,perl会自动的
将其初始化并将一个匿名的空项目引用赋值给它,如下:
my %provisions;
push @{ $provisions{'aa'} }, $1;
#等价于:
my %provisions;
$provisions{'aa'} = [  ];#键aa指向一个匿名空数组
push @{ $provisions{'aa'} }, $1;
#下面的例子,
my $top;
$top->[2]->[4] = 'lee-lou';
#等同于:
my $top = [undef, undef, [undef, undef, undef, 'lee-lou']];
#下面两个是等价的
my %total_bytes1;
$total_bytes1{'professor.hut'}{'gilligan.crew.hut'} += 1250;
%total_bytes2 = ('professor.hut'=>{'gilligan.crew.hut'=>1250});
#print Dumper(\%total_bytes1, \%total_bytes2);
99.函数引用:
sub add {
    my ($a, $b) = @_;
    $a + $b;
}
my $c = \&add;
print &$c(1, 2), "\n";
print &{$c}(1, 2), "\n";
print $c->(1, 2), "\n";
100.匿名函数:
my $func_add = sub {
    my ($a, $b) = @_;
    $a + $b;
};
my $c = $func_add->(1, 2);
print $c, "\n";
#作为回调函数使用:
use File::Find qw(find);
my @starting_directories = qw(.);
find(
  sub {
    print "$File::Find::name\n";
  },
  @starting_directories,
);
101.perl中,一个函数可以访问其函数体外部定义的变量,那么这个函数就被称为闭包
#闭包举例1,计算某个目录下所有文件的大小之和:
use File::Find qw(find);
my @starting_directories = qw(/usr/bin/);
my $total_size;
find(
  sub {
    $total_size += -s $File::Find::name;
  },
  @starting_directories,
);
print $total_size, "\n";
#闭包举例2,为文件夹下的每个文件编号:
use File::Find;
my $callback;
{
  my $count = 0;
  $callback = sub { print ++$count, ": $File::Find::name\n" };
}
#此处,虽然定义$count变量的代码块已经结束,已不能显式引用$count,
#但由于其被callback引用,因此在callback内部$count作为匿名变量依然有效
find($callback, '.');
#闭包举例3,将闭包函数作为函数返回值返回:
use File::Find;
sub create_callback {
  my $count = 0;
  return sub { print ++$count, ": $File::Find::name\n" };
}
my $callback = create_callback(  );
print "my bin:\n";
find($callback, '/bin');#第一批调用
print "my etc:\n";
find($callback, '/etc');#此处$callback内$count的值仍会保持$callback上次调用时的值
#闭包举例4,将闭包函数作为函数返回值返回:
use File::Find;
sub create_callback {
  my $count = 0;
  return sub { print ++$count, ": $File::Find::name\n" };
}
my $callback1 = create_callback();
my $callback2 = create_callback();
print "my bin:\n";
find($callback1, '/bin');
print "my etc:\n";
find($callback2, '/etc');#$callback1与$callback2是两个函数实例,各自内部维护了一个$count匿名变量
#闭包举例5,获取闭包函数返回值:
use File::Find;
sub create_callback {
  my $total_size = 0;
  return sub {
    if (@_) { # it's our dummy invocation
      return $total_size;
    } else { # it's a callback from File::Find:
      $total_size += -s if -f;
    }
  };
}
my $callback = create_callback(  );
find($callback, '/bin');
my $total_size = $callback->('dummy'); # dummy parameter to get size
print "total size of bin is $total_size\n";
#闭包举例6,获取闭包函数返回值:
use File::Find;
sub create_callbacks {
  my $total_size = 0;
  #两个回调函数访问同一个$total_size变量
  return (sub { $total_size += -s if -f }, sub { return $total_size });
}
my ($count_em, $get_results) = create_callbacks();
find($count_em, '/bin');
my $total_size = &$get_results();
print "total size of bin is $total_size\n";
#闭包举例7:
use File::Find;
sub print_bigger_than {
  my $minimum_size = shift;
  return sub { print "$File::Find::name\n" if -f and -s >= $minimum_size };
}
my $bigger_than_1024 = print_bigger_than(1024);
find($bigger_than_1024, '/bin');
#闭包举例8,非匿名的闭包:
#为$count提供了两个访问函数,同时保护了$count不被任何其他代码块私自修改,
#$count被叫做静态本地变量(static local variable)
BEGIN {#编译期立即执行(类似于java中的static代码块)
  my $count;
  sub count_one { ++$count }
  sub count_so_far { return $count }
}
count_one();
count_one();
print count_so_far(), "\n";
102.my与local的区分
使用local修饰某个变量,是为了告诉perl,如果此变量名已经被使用,
则暂时保存那个值直至使用相同变量名的局部变量失效。
103.文件句柄引用
#使用变量存储文件句柄
open my $log_fh, '>>', 'castaways.log'
        or die "Could not open castaways.log: $!";
log_message( $log_fh, 'My name is Mr. Ed' );
sub log_message {
  my $fh = shift;
  print $fh @_, "\n";
}
while( <$log_fh> ) { ... }#read something
#当文件句柄引用变量失效(超出作用范围)时,perl会自动关闭文件
204.目录句柄引用:
opendir my $dh, '.' or die "Could not open directory: $!";
foreach my $file  ( readdir( $dh ) ) {
    print "Skipper, I found $file!\n";
}
------------------------------------------------------------------------------
104.use的特点
use FirstModule ; # 导入 FirstModule 模块
# use 导入模块文件后缀必须为.pm,但 require 可以使用其他后缀
use v5.6.0 ; # 比较当前perl的版本号,如果比指定的版本小,便会产生严重错误,而中止程序
use FirstModule 2.0; # 比较倒入模块的版本 如果导入的模块的版本过低,便会产生严重错误,而中止程序
our $VERSION=2.0; # 设定当前模块的版本号
use FirstModule qw( @array ); #只从模块中导入指定的 @array 数组
no # 不从指定的名称空间里导入指定项目 ,语法等价于 use
use strict ;# 强迫声明时添加 作用域 全局或字典;强迫使用引号封闭字符串;强迫明确调用每个子程序。
use strict 'vars'; # 强迫声明时添加 作用域 全局或字典;
use strict 'subs';# 强迫使用引号封闭字符串;强迫明确调用每个子程序。
use vars qw( 变量1 变量2 ); # 声明全局变量
use warnings; # 打印警告信息
no strict; # 关闭语法检查
use constant PI => 3.1415926; # 创建常量标示符
use diagnostics; #启用诊断效果
  enable(); # 开启诊断
  disable(); # 禁用诊断
use integer; # 采用整数运算方式
105.perl中可以使用use、do或require来包含文件,三者的区别参见百度。
106.perl中包和模块的使用和区别,参照百度。
107.our和my的区别,包变量和词法变量的区别,参照百度。
108.使用@ISA数组来指定一个类的父类:
package Cow;
use base qw(Animal);#Perl 5.005 or earlier
#或
package Cow;
use Animal;
our @ISA = qw(Animal);#perl 5.6 or later
#或
package Cow;
use Animal;
@Cow::ISA = qw(Animal);
#或
package Cow;
use Animal;
use vars qw(@ISA);
@ISA = qw(Animal);
109.perl中类也是使用包来组织,因此,对于类中的方法,
可以使用->调用,也可以使用::来调用,但是两种调用方式是有区别的:
->是使用类名来调用,实参列表与形参列表不一致,实参列表的第一个元素是类名,是由perl默认传入的;
而::是通过包名来调用,此时被调用的函数就是一个普通的(面向过程的)函数,实参列表与形参列表一致,perl不会默认往参数列表顶端插入类名。
最终,不建议使用::来调用类中的方法,这样容易引起混乱。
110.子类调用父类的方法:
{ package Animal;
  sub speak {
    my $class = shift;
    print "a $class goes ", $class->sound, "!\n";
  }
}
{ package Mouse;
  use base qw(Animal);
  sub sound { 'squeak' }
  sub speak {
    my $class = shift;
    $class->SUPER::speak;#从@ISA中寻找第一个speak并调用
    print "[but you can barely hear it!]\n";
  }
}
Mouse->speak();
111.调用类方法的方式:
Class->method(@args);
#或
my $beast = 'Class';#使用字符串调用,恶心的perl!!!
$beast->method(@args);
112.在外部通过bless创建类实例:
{ package Mouse;
  sub speak {
    my $class = shift;
    print "squeak\n";
  }
}
my $name = 'Mr. Ed';
my $ins_mouse = \$name;
bless $ins_mouse, 'Mouse';
$ins_mouse->speak;#调用类实例的方法
print $$ins_mouse;#解引
112.在内部通过bless创建类实例(终于走向正轨了!):
{ package Horse;
  sub sound { 'neigh' }
  sub getName {
    my $self = shift;
    $self->{name};#解引
  }
  sub new {
    my $class = shift;
    my $name = shift;
    bless {'name'=>$name}, $class;#返回匿名类实例
  }
}
my $tv_horse = Horse->new('Mr. Ed');
print $tv_horse->getName;
114.对于调用类方法,
通过类名调用时,实参列表第一个元素是类名(字符串);
通过类实例调用时,实参列表第一个元素是类实例(bless过的引用)。
115.使用ref函数,可以区分一个变量是不是引用,因此,可以使用他来区分类实例和类名。
sub name {
  my $either = shift;
  ref $either
    ? $$either                # it's an instance, return name
    : "an unnamed $either";   # it's a class, return generic
}
116.在函数中,可以使用$_[0]来引用第一个参数,以此类推。
这个可以用在类的set和get方法中:
sub color     { $_[0]->{Color} }#第一个元素的类实例
sub set_color { $_[0]->{Color} = $_[1] }
117.类中可以定义DESTROY函数,当类实例被销毁时,perl会自动调用该函数;
只有没有任何强引用(与弱引用相对)指向某个类实例时,perl才会回收类实例,调用DESTROY函数。
如果perl未在类定义层次中找到DESTROY函数,perl并不会报错。
如果类实例中引用其他的类实例,perl会由外向里依次调用DESTORY函数,即先销毁外层,再销毁内层。
118.重写DESTROY函数时,一定要调用父类的(SUPER::DESTROY),否则可能销毁不完全。
119.另一种类函数调用方式:
my $obj = Some::Class->new(@constructor_params);
#等价于:
my $obj = new Some::Class @constructor_params;
120.perl中的弱引用(weak references):
#弱引用不会增加引用计数
#对象被回收时,指向他的弱引用会被赋值为undef。
## in Animal
use Scalar::Util qw(weaken); # in 5.8 and later
use WeakRef qw(weaken);      # in 5.6 after CPAN installation
our %REGISTRY;#记录每一个类实例
sub named {
  ref(my $class = shift) and croak 'class only';
  my $name = shift;
  my $self = { Name => $name, Color => $class->default_color };
  bless $self, $class;
  $REGISTRY{$self} = $self;#记录类实录,键是$self转化而成的唯一的字符串,值是类实例。
  weaken($REGISTRY{$self});#变成弱引用,以便perl能够正常的回收。
  $self;
}
121.Perl 所有模块都隐含的继承了一个称作 UNIVERSAL的内建模块,并继承了如下三个方法:
isa(包名)
例如:如果Rectangle模块继承了(无论是以间接的方法)Shape 模块,Rectangle->isa(‘Shape’) 将返回true
can(函数名)
如果Rectangle 或它的任何基类包含有名为draw的函数,Rectangle->can(‘draw’)将返回true
VERSION(版本号)
可以给UNIVERSAL添加新的方法。一旦给它添加了新的方法,所有的class都可以调用。
给UNIBERSAL添加新方法的例子:
sub UNIVERSAL::log() {
    my($self,$msg)=@_;
    print "$self: $msg\n";
}
122.调用某个对象的方法时,perl首先会在类层次间查找,如果没找到,会继续查找
UNIVERSAL基类;如果还未查找到,perl会重新在类层次及UNIVERSAL基类中查找AUTOLOAD函数,
如果找到,则会在原先的目标函数处直接调用AUTOLOAD函数,并传入参数列表,跟普通类方法一样,
实参列表第一个元素为类实例或类名,并将原先的目标函数的函数名赋值给$AUTOLOAD包变量。
123.可以在AUTOLOAD函数中定义目标子函数,以实现按需编译、安装的功能:
## in Animal
sub AUTOLOAD {
  our $AUTOLOAD;
  (my $method = $AUTOLOAD) =~ s/.*:://s; # remove package name
  if ($method eq "eat") {## define eat:
    eval q{
      sub eat {
        #...
        #long definition goes here
        #...
      }
    };                # End of eval's q{  } string
    die $@ if $@;                        # if typo snuck in
    goto &eat;                           # jump into it
  } else {                               # unknown method
    croak "$_[0] does not know how to $method\n";
  }
}
#如上,当第一次调用Animal::eat函数时,eat并不存在,因此进入AUTOLOAD,在AUTOLOAD中,
通过eval动态定义了eat,然后调用之;此后,当再次调用eat时,因为eat已被定义,就不会进入AUTOLOAD函数了。
124.使用AUTOLOAD简化get、set方法:
sub AUTOLOAD {
my @elements = qw(color age weight height);
our $AUTOLOAD;
if ($AUTOLOAD =~ /::get(\w+)$/ and grep lcfirst($1) eq $_, @elements) {
  my $field = lcfirst $1;
  {
    no strict 'refs';
    *{$AUTOLOAD} = sub { $_[0]->{$field} };
  }
  goto &{$AUTOLOAD};
} elsif ($AUTOLOAD =~ /::set(\w+)$/ and grep lcfirst($1) eq $_, @elements) {
  my $field = lcfirst $1;
  {
    no strict 'refs';
    *{$AUTOLOAD} = sub { $_[0]->{$field} = $_[1] };
  }
  goto &{$AUTOLOAD};
} else {                               # unknown method
    croak "$_[0] does not know how to $method\n";
}
125.引入模块时,下面两段代码是等价的:
use Island::Plotting::Maps qw( load_map scale_map draw_map );
#等价于:
BEGIN {
  require Island::Plotting::Maps;
  Island::Plotting::Maps->import( qw( load_map scale_map draw_map ) );
}
126.自定义模块时,可以继承Exporter模块,使用其定义的import方法来导出向调用者导出需要的函数,
@EXPORT数组用于定义默认向外导出的函数列表,@EXPORT_OK用于定义其他的可以向外导出的函数列表。
如下:
package Navigate::SeatOfPants;
our @EXPORT = qw(guess_direction_toward);
our @EXPORT_OK = qw(ask_the_skipper_about get_north_from_professor);
use base qw(Exporter);
#外界调用时如下:
use Navigate::SeatOfPants;  # gets guess_direction_toward
use Navigate::SeatOfPants qw(guess_direction_toward); # same
use Navigate::SeatOfPants
  qw(guess_direction_toward ask_the_skipper_about);
use Navigate::SeatOfPants
  qw(ask_the_skipper_about get_north_from_professor);## does NOT import guess_direction_toward!
127.%EXPORT_TAGS哈希表用于定义导出标签:
package Navigate::SeatOfPants;
use base qw(Exporter);
our @EXPORT    = qw(guess_direction_toward);
our @EXPORT_OK = qw(
                get_north_from_professor
                according_to_GPS
                ask_the_skipper_about
                );
our %EXPORT_TAGS = (
        all       => [ @EXPORT, @EXPORT_OK ],
        gps       => [ qw( according_to_GPS ) ],
        direction => [ qw(
                get_north_from_professor
                according_to_GPS
                guess_direction_toward
                ask_the_skipper_about
                ) ],
        );
#外界调用时如下:
use Navigate::SeatOfPants qw(:direction);


© 著作权归作者所有

共有 人打赏支持
hunterli
粉丝 36
博文 87
码字总数 14683
作品 0
大连
程序员
语言学习读书笔记PHP和asp.net编程语言哪个更有前途?

编程语言一直是学习计算机编程门专业的热门讨论话题,而我也选择了这个专业,入学一年了,马上面临着语言的选择问题,业余我需要选择一门编程语言作为重点研究对象,那么问题来了:到底是选择...

原创小博客
05/30
0
0
UNIX网络编程卷2进程间通信读书笔记汇总

UNIX网络编程卷2进程间通信读书笔记(一)—概述 http://blog.chinaunix.net/u/22935/article527112.html UNIX网络编程卷2进程间通信读书笔记(二)—管道 (1) http://blog.chinaunix.net/...

长平狐
2012/09/03
185
0
如何用jq实现把该数组转换成下方数组的方式

如何用jq实现把该数组转换成下方数组的方式: lists:[ {id:1,target:1,logType:"type1",createTime:1523614887142,description:"读书笔记1",code:""}, {id:2,target:1,logType:"type1",creat......

heyujun-
04/13
0
0
如何处理分页api以天为单位输出

@蓝水晶飞机 你好,想跟你请教个问题: 如果后台api返回的数据一下格式且分页: lists:[ {id:1,target:1,logType:"type1",createTime:1523614887142,description:"读书笔记1",code:""}, {id:...

heyujun-
04/15
0
0
读书笔记:架构之道(V1.0)

读书笔记:架构之道(V1.0) ShareCore2014-10-19281 阅读 读书笔记架构 下载链接:读书笔记:架构之道(v1.0).xmind Included file ‘post/copyright.html’ not found in _includes directory 点...

ShareCore
2014/10/19
0
0
用骆驼祥子读书笔记来解答ZBLOG博客写作的3个技巧[图]

建设博客已经半年了,准确的说应该是7个月了吧,虽然没有取得什么好的进展,但毕竟一直在努力,主要是内容建设上比较麻烦,很难像大站一样获得大量的内容,这是非常头疼的问题。 总之,个人也...

原创小博客
07/11
0
0
告诉你1年读100本书的方法

《书都不会读,你还想成功》是一本小说,由韩国作家二志成和郑会一合著,书的内容为一个焦躁的职场人士通过读书的方式,彻底改变了自己的思维方式,进而改变了自己的生活的故事。 下面就说说...

anda0109
2016/12/22
0
0
2018开始读书吧——关于读书的思考

1.封目序尾 所谓的封目序尾就是:读书前要先看封面、目录、序言、结尾。 封面:题目是作者花了很长的时间才总结出的,是对这本书的一句话概括,是这本书的核心价值。 目录:是对这本书的梳理...

尚洪范
01/03
0
0
敏捷教练成长记:平安夜中第八周

这是第八周,也是平安夜,愿大家平安。 上周计划完成情况 1、敏捷方面读不少于50页的书或者文章。 - 读了修改代码的艺术,暂未输出读书笔记。 - 完成《家长学校读本(一年级)》阅读,并输出...

通爸
2017/12/24
0
0
《数据之巅》读书笔记

《数据之巅》读书笔记 笑遍世界2017-05-1311 阅读 大数据读书笔记 2016年初读的徐子沛的一本书《数据之巅》,把读书笔记记录一下。 美国国会实行参众两院制,众议院的席位按人口比例在各州之...

笑遍世界
2017/05/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Weblogic问题解决记录

问题:点击登录,页面刷新但是不进去管理界面。解决:删除cookies再登录。

wffger
25分钟前
0
0
RxJava2的错误处理方案

最近使用retrofit2 + rxKotlin2写接口访问,想尽量平铺代码,于是就想到当借口返回的状态码为「不成功」时(比如:code != 200),就连同网络错误一起,统一在onError方法中处理。想法总是好的...

猴亮屏
33分钟前
0
0
程序的调试信息

调试二进制程序时,经常要借助GDB工具,跟踪程序的执行流程,获取程序执行时变量的值,以发现问题所在。GDB能得到这些信息,是因为编译程序时,编译器保存了相应的信息。Linux下的可执行程序...

qlee
56分钟前
0
0
应用级缓存

缓存命中率 从缓存中读取数据的次数与总读取次数的比例,命中率越高越好 java缓存类型 堆缓存 guavaCache Ehcache3.x 没有序列化和反序列化 堆外缓存ehcache3.x 磁盘缓存 存储在磁盘上 分布式...

writeademo
今天
0
0
python爬虫日志(3)find(),find_all()函数

1.一般来说,为了找到BeautifulSoup对象内任何第一个标签入口,使用find()方法。 以上代码是一个生态金字塔的简单展示,为了找到第一生产者,第一消费者或第二消费者,可以使用Beautiful Sou...

茫羽行
今天
0
0
java:thread:顺序执行多条线程

实现方案: 1.调用线程的join方法:阻塞主线程 2.线程池 package com.java.thread.test;public class MyThread01 implements Runnable {@Overridepublic void run() {Syste...

人觉非常君
今天
0
0
ElasticSearch 重写IK分词器源码设置mysql热词更新词库

常用热词词库的配置方式 1.采用IK 内置词库 优点:部署方便,不用额外指定其他词库位置 缺点:分词单一化,不能指定想分词的词条 2.IK 外置静态词库 优点:部署相对方便,可以通过编辑指定文...

键走偏锋
今天
19
0
Git 2.18版本发布:支持Git协议v2,提升性能

Git 2.18版本发布:支持Git协议v2,提升性能Git 2.18版本发布:支持Git协议v2,提升性能 新版本协议的主要驱动力是使 Git 服务端能够对各种 ref(分支与 tag)进行过滤操作。 这就意味着,G...

linux-tao
今天
0
0
python浏览器自动化测试库【2018/7/22-更新】

64位py2.7版本 更新 document_GetResources 枚举页面资源 document_GetresourceText 获取指定url的内容 包括页面图片 下载地址下载地址 密码:upr47x...

开飞色
今天
44
0
关于DCL双重锁失效及解决方案

关于DCL双重锁失效及解决方案 Double Check Lock (DCL)实现单例 DCL 方式实现单例的优点是既能够在需要时才初始化单例,又能够保证线程安全,且单例对象初始化后调用getInstance方法不进行...

DannyCoder
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部