<Perl语言入门>读书笔记 | 四. 子程序
2016-02-26 01:52
246 查看
其实就是所谓的函数。
子程序最后一次运算的结果,会被自动当成子程序的返回值。当然,也可以使用return关键字。
$_[0]和$_[1]、@_ 都是函数的私有变量,不会受外界影响。默认情况下,Perl里面的所有变量都是全局变量,哪怕是在函数里创建的。这是一件很危险的事。如果不小心又创建了一个之前出现过的同名变量的话,很容易在无意间就改变了之前出现过的这个变量的值。通过my关键字,可以创建私有变量,和全局变量两不相犯,从而避免了这种情况。
一个改进的、可以接受任意个参数的max函数如下,这个算法的名字很有意思。“高水线(high-watermark)”:大水过后,在最后一波浪消退时,高水线会标示出所见过的最高水位。
在日常编程中,最好将每个新变量都使用my声明,让它保持在自己所在的词法作用域内。
use strict关键字:编译器会强制使用一些严格的、良好的编程风格。比如,变量要先声明(用my关键字),后使用:
以上代码没有加my的话,就会报错:
Global symbol “$vivi” requires explicit package name (did you forget to declare “my $vivi”?)
如果自己定义的子程序与Perl内置函数同名的话,为了调用自己定义的子程序,就必须加$号。所以更一般的情况是,调用自建函数时务必使用$号,除非你很确定Perl所有的内置函数名没有与你的自建函数同名。
这段代码输出1和2,$n是全局变量。但是加上use strict;后,这段代码将出错,因为$n没有被定义。但是如果将$n定义为my,每次函数执行完成后,$n的内容会被清空,输出结果就会变成1和1。为了保留函数结果,我们使用state关键字来声明持久性私有变量。
第一次调用这个子程序时,Perl声明并初始化变量$n,而在接下来的调用中,这个声明表达式将被Perl忽略。每次子程序返回后,$n的当前值都会被保留下来,以备下次调用时再用。
state关键字的用法和my基本相似,但是不能在列表上下文中初始化数组类型的state变量。
1. 子程序基础
子程序中可以使用任何全局变量;子程序最后一次运算的结果,会被自动当成子程序的返回值。当然,也可以使用return关键字。
sub max{ if($_[0] > $_[1]){ $_[0] }else{ $_[1] } } print &max(3, 5);
$_[0]和$_[1]、@_ 都是函数的私有变量,不会受外界影响。默认情况下,Perl里面的所有变量都是全局变量,哪怕是在函数里创建的。这是一件很危险的事。如果不小心又创建了一个之前出现过的同名变量的话,很容易在无意间就改变了之前出现过的这个变量的值。通过my关键字,可以创建私有变量,和全局变量两不相犯,从而避免了这种情况。
sub max{ if(@_ != 2){ # 判断参数个数 print "Error\n" } my($m, $n) = @_; # 创建新的私有变量,并将参数赋值给变量 if($m > $n){ $m }else{ $n } } print &max(3, 5);
一个改进的、可以接受任意个参数的max函数如下,这个算法的名字很有意思。“高水线(high-watermark)”:大水过后,在最后一波浪消退时,高水线会标示出所见过的最高水位。
sub max{ my($max_so_far) = shift @_; # 数组中的第一个值,暂时当它最大 foreach (@_){ if($_ > $max_so_far){ $max_so_far = $_; } } $max_so_far; } print &max(3, 5, 10, 4, 6);
2. my关键字
my关键字不会更改变量赋值时的上下文:my ($num) = @_; # 列表上下文,和($num) = @_; 相同, $num被设为数组的第一个数 my $num = @_; # 标量上下文,和 $num = @_; 相同, $sum被设为数组的大小
在日常编程中,最好将每个新变量都使用my声明,让它保持在自己所在的词法作用域内。
foreach my $rock (qw{a b c}){ print $rock; }
use strict关键字:编译器会强制使用一些严格的、良好的编程风格。比如,变量要先声明(用my关键字),后使用:
use strict; my $vivi = 3; $vivi += 1;
以上代码没有加my的话,就会报错:
Global symbol “$vivi” requires explicit package name (did you forget to declare “my $vivi”?)
3. 省略函数调用的$号
在不加$号也不会产生歧义的情况下,函数调用时函数名前的$号是可以省略的。如下面这种情况,函数shift不仅可以省略$号,连参数列表两边的括号都可以省略:use strict; my @array = qw(a b c); my @dealed = shift @array;
如果自己定义的子程序与Perl内置函数同名的话,为了调用自己定义的子程序,就必须加$号。所以更一般的情况是,调用自建函数时务必使用$号,除非你很确定Perl所有的内置函数名没有与你的自建函数同名。
4. state关键字
sub marine{ $n += 1; print "$n\n" } &marine; &marine;
这段代码输出1和2,$n是全局变量。但是加上use strict;后,这段代码将出错,因为$n没有被定义。但是如果将$n定义为my,每次函数执行完成后,$n的内容会被清空,输出结果就会变成1和1。为了保留函数结果,我们使用state关键字来声明持久性私有变量。
use strict; use feature 'state'; sub marine{ state $n = 0; $n += 1; print "$n\n"; } &marine; &marine;
第一次调用这个子程序时,Perl声明并初始化变量$n,而在接下来的调用中,这个声明表达式将被Perl忽略。每次子程序返回后,$n的当前值都会被保留下来,以备下次调用时再用。
state关键字的用法和my基本相似,但是不能在列表上下文中初始化数组类型的state变量。
use strict; use feature 'state'; my @array = qw(a b c); # 正确 state @array = qw(a b c); # 错误
课后习题
(1)
use strict; use feature 'state'; sub total{ my($sum) = 0; foreach (@_){ $sum += $_; } $sum; } my @fred = qw{1 3 5 7 9}; print &total(@fred);
(2)
use strict; use feature 'state'; sub total{ my($sum) = 0; foreach (@_){ $sum += $_; } $sum; } my @fred = 1..1000; print &total(@fred);
(3)
use strict; use feature 'state'; sub average{ my $n = @_; my($sum) = 0; foreach (@_){ $sum += $_; } $sum / $n; } sub above_average{ my $avg = &average(@_); foreach (@_){ if($_ > $avg){ print "$_\t"; } } } my @fred = 1..10; print &above_average(@fred);
(4)
use strict; use feature 'state'; sub greet{ my ($guest) = @_; state $last; if($last eq undef){ print "Hi $guest! You are the first one here!\n"; }else{ print "Hi $guest! $last is also here!\n"; } $last = $guest; } &greet("Fred"); &greet("Barney");
(5)
use strict; use feature 'state'; sub greet{ my ($guest) = @_; state @last; if(@last == 0){ print "Hi $guest! You are the first one here!\n"; }else{ print "Hi $guest! I've seen: "."@last\t"."\n"; } push @last, $guest; } &greet("Fred"); &greet("Barney"); &greet("Wilma"); &greet("Betty");
参考文献
Perl语言入门 第六版中文清晰PDF相关文章推荐
- MyEclipse使用Maven创建web项目+搭建SSM框架教程
- 常见的UNIX命令
- 《python核心编程》--读书笔记 第21章 数据库编程
- 几种常用 css3 选择器解释
- 保存数据时报:Incorrect string value: '\xF0\x9F\x91\x8D' for column 'f_char_name' at row 1
- 使用BP神经网络做预测
- android底层开发笔记(1)解析android编译
- Fragment 操作原理
- 【CSS3】box-sizing 属性
- □□□ + □□□ = □□□
- Matlab做快速傅里叶变换
- 将二叉树拆成链表 Flatten Binary Tree to Linked List
- Window消息机制
- 冒泡,选择,插入排序的效率比较
- CentOS下NTP时间服务器的架设和Windows客户端的配置(三)Windows客户端配置
- 关于Spring+Mybatis打印日志的问题
- 【CSS3】CSS生成内容:content
- 挨踢职场求生法则-----我在IT职场打滚超过15年了,从小小的程序员做到常务副总
- 判断int类型是否为空
- 为你的Android应用定制属于你的BaseActivity http://blog.csdn.net/jiahui524