perl学习笔记-----------------------(16)
2017-04-22 00:00
274 查看
当传递数组或者哈希表时,它将复制到@_中,这对于单个数组没有问题,但哈希表将被展开为键/值组合的列表。在子程序中将@_赋值给哈希表是可行的,通过初始化的方法:通过将键/值组合表赋值给它。下面例子想子程序printem传递给了哈希表,这个子程序将打印哈希表的所有元素:
PS:因为传递给子程序的参数会展开到一个平面列表中,如果传递了两个或则跟多的数组或哈希表,则那些数组或者哈希表中的元素将会构成@_中长长列表。
PS:为了在传递数组或者哈希表的时候保持各自的完整性,要按引用传递给他们。(按引用传递 按引用返回)
使用不同个数的参数:参数是在@_数组中传递的,perl可以很轻松的向子程序传递个数不同的参数。为了确定传递了多少个参数,仅需检查数组长度$_(PS,$_是@_中最后一个元素的下标值,所以$加1就得到了基于0的数组@_中的元素总数)。
为参数设置默认值:||=运算符为用户可能忽略的参数提供默认值:
列表赋值使变量$value2为零时,为变量提供了默认值1。在传递5这个值时的到5+1=6;
PS:假设用户不会传递值0或者空字符串。更好的方法是使用defined函数:
在某些情况下,可选择参数处于参数列表末尾,可以明确检查@_中元素的个数,也就是$_+1,以了解用户传递了多少个参数:
子程序的返回值就是计算的最后一个表达式,或者可以用return语句明确退出子程序,并指定返回值。返回值在适当的上下文中计算,这取决于子程序调用的上下文。
------------------------------------------------Demo-----------------------------------------------
返回哈希表
返回undef指出操作失败:编写一个函数getdata,它从文件中读取数据。然而,如果在文件中读取数据时出现了问题,getdata将返回undef。
PS:这个例子使用eval函数来捕获错误,所以它不会对程序造成致命影响,而且可以通过检查$@a中的值,而了解是否出现了错误,eval将所有的错误都放在$@中:
用my设置范围:默认情况下,perl中的变量是全局性的。使用my关键字可以将变量限制在封闭的程序块、条件、循环、子程序、eval语句、或者用do、require、use包含的文件中。my声明的变量具有“词汇意义的”范围,local声明的变量具有动态范围。
my与local的主要差异在:具有动态范围的变量在变量范围内调用的子程序是可以看见的。而具有词汇意义范围的变量并不是这样。使用子程序的结果就是用my声明的变量将完全局限于子程序内使用。为了用my声明数量值,以限制标量值的范围,需使用my $scalar。如果用my列出了多个元素,则列表必须出现在括号中。和my一起使用的所有元素都必须是合法的左值。
PS:只有数字字母标识符可以具有词汇范围,诸如$_这样的特殊内置元素必须使用local声明。
----------------------------------------------------------------DEMO-----------------------------------------------------------------------
声明为词汇范围的变量并没有限制在代码块中,相关的控制表达式也词汇范围的组成部分。
要求词汇范围的变量:把所用的全部变量都作为词汇范围的变量,可以使用附注:use strict 'vars'。这样,将从那个点开始到封闭程序块或者范围末尾之间对变量的任何引用,都必须引用专门声明的词汇变量,或者必须用它的包名称来限定。
local创建临时变量:local创建动态范围变量,建立全局变量的临时副本,并使用这个临时副本,直至超出范围(那时,将恢复全局变量的值)必须使用local的地方:创建类似$_特殊变量的局部副本、修改数组或哈希表中的一个元素、局部使用文件句柄和perl格式。
PS:local并不会创建变量,只创建全局变量的副本(而且保留全局变量的值,以供本地副本超出范围时候恢复)使用local将建立所列变量的副本,并使它们局限于封闭的程序块、eval语句、do语句、从那个块内调用的任何子程序。
-----------------------------------------------------Demo-----------------------------------------------------------
确定my和local之间的差别:my创建了一个新变量,local将保存现存变量的副本。local是运行期间的结构,而不是编译期间的结构,用local对全局变量你的改动在通过子程序调用离开局部范围时任然有效。通常情况下,应该使用my,而不是local。my的执行速度快,而且没有全局副作用。然而,注意,必须使勇local来局部化任何以$开头的特殊变量。用my声明的变量存储在专用符号表中,而不是作为整个包的符号表的组成部分。
用our设置变量:处理全局变量。our声明方法声明了变量在封闭的程序块、文件或者eval语句内是合法的全局变量。our不会创建任何局部变量。
----------------------------------------------------Demo-----------------------------------------------
创建永久(静态)变量:有时候希望让子程序中的变量在两次调用子程序之间保留它的值,然而,如果用my或者local在子程序中声明变量,这些变量将在每次进入子程序的时候重置。
--------------------------------------Demo--------------------------------------
如果$count成为静态变量可以解决这个问题,但perl不直接支持静态变量,默认情况下,全局变量是静态的,但用my声明的子程序变量不是静态的。词汇变量只要处于范围之内就不会重置。将my声明放在子程序外进行,然后将代码(声明和子程序)都放在括号内,这使得它的层次和对子程序的调用的层次相同:
也可以将所有内容放在BEGIN块中,这个块将在程序加载的时候运行:
得到子程序的名称和caller:caller函数返回当前子程序上下文的信息。一般情况下,可以这样使用caller:
在标量上下文中,如果在子程序使用,则返回主调代码包的名称,或者返回eval或者requore,否则返回不确定的值。
在表上下文中,这个函数像这样返回列表:
如果包含了EXPR,则caller返回其他信息,调试人员可以用这些信息打印堆栈跟踪记录。EXPR的值说明在当前堆栈架之前有多少堆栈框架需要返回(也就是子程序调用)。
----------------------------------------------------Demo--------------------------------------
递归调用子程序:
在递归的情况下,需要my来局部化变量
嵌套子程序:perl支持嵌套子程序,可以在子程序的内部嵌套子程序。
----------------------------------Demo----------------------------------------
内联函数:如果函数的原型是(),既没有任何参数,则该函数在perl便以其中就是内联的。这样的函数必须由常量或者词汇范围内的标量构成。不能用&或者do引用。
覆盖内置子程序:当覆盖子程序时,就为它提供了一个新定义。可以覆盖子程序,包括内置在perl中的函数,但仅能覆盖从模块中导入的子程序。
可以使用subs附注用导入语法预先声明子程序,可以使用那些名称来覆盖内置函数。
---------------------------覆盖内置子程序例子-----------------------------------------
重新定义子程序:
$hash{fruit}=peach; $hash{vegetable}=broccoli; $hash{pie}=blueberry; sub printem { $hash=@_; foreach $key(keys %hash){ print "$key=>$hash{$key}\n"; } } printem(%hash);
PS:因为传递给子程序的参数会展开到一个平面列表中,如果传递了两个或则跟多的数组或哈希表,则那些数组或者哈希表中的元素将会构成@_中长长列表。
PS:为了在传递数组或者哈希表的时候保持各自的完整性,要按引用传递给他们。(按引用传递 按引用返回)
使用不同个数的参数:参数是在@_数组中传递的,perl可以很轻松的向子程序传递个数不同的参数。为了确定传递了多少个参数,仅需检查数组长度$_(PS,$_是@_中最后一个元素的下标值,所以$加1就得到了基于0的数组@_中的元素总数)。
sub addem_4 { print "You passed ".($_+1)." element.\n"; foreach $element(@_){ $sum+=$element; } print join(" ,",@_)."=$sum\n"; } addem_4(2,3,4);
为参数设置默认值:||=运算符为用户可能忽略的参数提供默认值:
sub addem_5 { ($value1,$value2)=@_; $value2 ||=1; print "\$value1+\$value2=". ($value1+$value2) ."\n"; } addem_5(5);
列表赋值使变量$value2为零时,为变量提供了默认值1。在传递5这个值时的到5+1=6;
PS:假设用户不会传递值0或者空字符串。更好的方法是使用defined函数:
sub addem_6 { ($value1,$value2)=@_; if(!defined($value2)){ $value2 =1; }; print "\$value1+\$value2=". ($value1+$value2) ."\n"; } addem_6(6);
在某些情况下,可选择参数处于参数列表末尾,可以明确检查@_中元素的个数,也就是$_+1,以了解用户传递了多少个参数:
sub addem_7 { $value1==shift @_; if($_>0){ $value2 =@_[1]; }else{ $value2=1; }; print "\$value1+\$value2=". ($value1+$value2) ."\n"; } addem_7(7);
子程序的返回值就是计算的最后一个表达式,或者可以用return语句明确退出子程序,并指定返回值。返回值在适当的上下文中计算,这取决于子程序调用的上下文。
------------------------------------------------Demo-----------------------------------------------
返回哈希表
sub gethash { $hash{fruit}=peach; $hash{fruit1}=peach1; $hash{fruit2}=peach2; $hash{fruit3}=peach3; $hash{fruit4}=peach4; return %hash; } %myhash=gethash; foreach $key(keys %myhash){ print "$key=>$myhash{$key}\n"; }
返回undef指出操作失败:编写一个函数getdata,它从文件中读取数据。然而,如果在文件中读取数据时出现了问题,getdata将返回undef。
PS:这个例子使用eval函数来捕获错误,所以它不会对程序造成致命影响,而且可以通过检查$@a中的值,而了解是否出现了错误,eval将所有的错误都放在$@中:
sub getdata { open FILEHANDLE ,"<nonexist.dat>"; $line=<FILEHANDLE> if FILEHANDLE; } if($@){ return; }else{ return $line; } $data=getdata(); if(defined($data)) { print $data; }else{ print "Sorry,getdata failed!\n"; }
用my设置范围:默认情况下,perl中的变量是全局性的。使用my关键字可以将变量限制在封闭的程序块、条件、循环、子程序、eval语句、或者用do、require、use包含的文件中。my声明的变量具有“词汇意义的”范围,local声明的变量具有动态范围。
my与local的主要差异在:具有动态范围的变量在变量范围内调用的子程序是可以看见的。而具有词汇意义范围的变量并不是这样。使用子程序的结果就是用my声明的变量将完全局限于子程序内使用。为了用my声明数量值,以限制标量值的范围,需使用my $scalar。如果用my列出了多个元素,则列表必须出现在括号中。和my一起使用的所有元素都必须是合法的左值。
PS:只有数字字母标识符可以具有词汇范围,诸如$_这样的特殊内置元素必须使用local声明。
----------------------------------------------------------------DEMO-----------------------------------------------------------------------
sub printhem { my $inner=shift @_; print $inner; } printhem "Hello\n"; print $inner; PS:my仅适用于标量值、数组和哈希表 my $variable; my ($variable1,$variable2); my $variable=5; my @array=(1,2,3); my %hash;
声明为词汇范围的变量并没有限制在代码块中,相关的控制表达式也词汇范围的组成部分。
要求词汇范围的变量:把所用的全部变量都作为词汇范围的变量,可以使用附注:use strict 'vars'。这样,将从那个点开始到封闭程序块或者范围末尾之间对变量的任何引用,都必须引用专门声明的词汇变量,或者必须用它的包名称来限定。
local创建临时变量:local创建动态范围变量,建立全局变量的临时副本,并使用这个临时副本,直至超出范围(那时,将恢复全局变量的值)必须使用local的地方:创建类似$_特殊变量的局部副本、修改数组或哈希表中的一个元素、局部使用文件句柄和perl格式。
PS:local并不会创建变量,只创建全局变量的副本(而且保留全局变量的值,以供本地副本超出范围时候恢复)使用local将建立所列变量的副本,并使它们局限于封闭的程序块、eval语句、do语句、从那个块内调用的任何子程序。
-----------------------------------------------------Demo-----------------------------------------------------------
sub printifok { local $local_value=$V_value; if($local_value>10){ print "V_value is $V_value.\n"; }else{ print "V_value is too small.\n"; } } $V_value=10; printifok; $V_value=12; printifok;
确定my和local之间的差别:my创建了一个新变量,local将保存现存变量的副本。local是运行期间的结构,而不是编译期间的结构,用local对全局变量你的改动在通过子程序调用离开局部范围时任然有效。通常情况下,应该使用my,而不是local。my的执行速度快,而且没有全局副作用。然而,注意,必须使勇local来局部化任何以$开头的特殊变量。用my声明的变量存储在专用符号表中,而不是作为整个包的符号表的组成部分。
用our设置变量:处理全局变量。our声明方法声明了变量在封闭的程序块、文件或者eval语句内是合法的全局变量。our不会创建任何局部变量。
----------------------------------------------------Demo-----------------------------------------------
package package1; $value_1=5; package package2; print "\$value_1 =" .$value_1; package package1; our $value_1; $value_1=5; package package2; print "\$value_1 =" .$value_1."\n";
创建永久(静态)变量:有时候希望让子程序中的变量在两次调用子程序之间保留它的值,然而,如果用my或者local在子程序中声明变量,这些变量将在每次进入子程序的时候重置。
--------------------------------------Demo--------------------------------------
sub incrementcount { my $count; return ++$count; } print incrementcount ."\n"; print incrementcount ."\n"; print incrementcount ."\n"; print incrementcount ."\n";
如果$count成为静态变量可以解决这个问题,但perl不直接支持静态变量,默认情况下,全局变量是静态的,但用my声明的子程序变量不是静态的。词汇变量只要处于范围之内就不会重置。将my声明放在子程序外进行,然后将代码(声明和子程序)都放在括号内,这使得它的层次和对子程序的调用的层次相同:
{ my $count; sub incrementcount { return ++$count; } } print incrementcount ."\n"; print incrementcount ."\n"; print incrementcount ."\n"; print incrementcount ."\n";
也可以将所有内容放在BEGIN块中,这个块将在程序加载的时候运行:
sub BEGIN { my $count; sub incrementcount { return ++$count; } print incrementcount ."\n"; print incrementcount ."\n"; print incrementcount ."\n"; print incrementcount ."\n"; }
得到子程序的名称和caller:caller函数返回当前子程序上下文的信息。一般情况下,可以这样使用caller:
caller EXPR caller
在标量上下文中,如果在子程序使用,则返回主调代码包的名称,或者返回eval或者requore,否则返回不确定的值。
在表上下文中,这个函数像这样返回列表:
($package,$filename,$line)=caller;
如果包含了EXPR,则caller返回其他信息,调试人员可以用这些信息打印堆栈跟踪记录。EXPR的值说明在当前堆栈架之前有多少堆栈框架需要返回(也就是子程序调用)。
($package,$filename,$line,$subroutine,$hasargs,$wantarray,$evaltext,$is_require)=caller($s);
----------------------------------------------------Demo--------------------------------------
sub addem_1 { ($value_1,$value_2) = @_; $value_1+$value_2; print join(" ,",caller); } $value_3=addem_1(2,2);
递归调用子程序:
sub factorial { my $value=shift (@_); return $value== 1? $value:$value * factorial ($value-1); } $result_1=factorial(6); print $result_1."\n";
在递归的情况下,需要my来局部化变量
嵌套子程序:perl支持嵌套子程序,可以在子程序的内部嵌套子程序。
----------------------------------Demo----------------------------------------
sub outer { my $s="Inside the inner subroutine.\n"; sub inner { my $s2=$s; print $s2; } inner(); } outer();
内联函数:如果函数的原型是(),既没有任何参数,则该函数在perl便以其中就是内联的。这样的函数必须由常量或者词汇范围内的标量构成。不能用&或者do引用。
覆盖内置子程序:当覆盖子程序时,就为它提供了一个新定义。可以覆盖子程序,包括内置在perl中的函数,但仅能覆盖从模块中导入的子程序。
可以使用subs附注用导入语法预先声明子程序,可以使用那些名称来覆盖内置函数。
---------------------------覆盖内置子程序例子-----------------------------------------
sub subs 'exit'; sub exit { print "Do you really want to exit?"; $answer= <>; if($answer =~ m/^y/i){ CORE::exit; } } while(1){ exit; };
重新定义子程序:
{ #----------------------创建子程序sub_1----------------------- my $text=shift; sub sub_1 { $text=shift; print "$text there!\n"; } #----------------------创建子程序sub_2----------------------- sub sub_2 { $text=shift; print "$text everyone!\n"; } #-----调用sub_1,重新定义它,使得它引用sub_2,并再次调用它------- sub_1("Hello"); *sub_1=\&sub_2; sub_1("Hello"); }
相关文章推荐
- Perl 学习笔记 --- 16
- perl学习笔记-----------------------(16)
- perl学习笔记16--Web自动化和连网
- Perl 学习笔记 1 ------ 初探 Perl
- Asp.Net Ajax 学习笔记16 Profile Service扩展方式
- perl学习笔记七----文件
- perl学习笔记八----格式化输出
- perl学习笔记(一)
- perl学习笔记(一)
- PERL学习笔记[不完整版]
- perl学习笔记六----函数
- perl学习笔记 (1)perl常识
- 转载 bigtiger perl 学习笔记
- Perl学习笔记(2)
- C#面向对象设计模式纵横谈 学习笔记16 Interpreter 解释器模式(行为型模式)
- Symbian学习笔记(16) - 解析XML文件(下)
- perl学习笔记一----变量
- perl学习笔记二----列表和数组
- perl学习笔记九----特殊变量
- perl学习笔记(二)