Perl子程序

本文详细介绍了Perl子程序的定义、调用与返回值,包括子程序的基本属性、参数传递、变量使用,以及中级用法如use strict编译指令和子程序签名等,强调了子程序在不同场景下的应用和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Perl子程序

1. 子程序的基本属性

1.1 子程序的定义

  • 要定义子程序,首先要以关键字 sub 开头,再加上子程序名,花括号,花括号中包含的是函数的主体。
  • 子程序可以被定义在程序的任意位置;不需要对子程序进行事先声明;
  • 子程序是全局的,如果定义了两个重名的子程序,后面的子程序会覆盖前面的那个;
#a simple subroutine
sub marine{
	$n += 1;
	print "$n time call marine subroutine.\n";
}

1.2 子程序的调用和返回值

  • 子程序调用:在任意表达式中,子程序前面的 & 表示调用这个子程序;如 &marine
  • 子程序返回值(标量):
    • Perl中子程序没有 “有无返回值” 的区别;
    • 任何时候子程序都有返回值,但有时这个值并没有什么用处,每次都写返回值return就显得十分麻烦;
    • Perl将子程序执行的最后一次运算的 “结果” ,结果不一定是数值计算得到,当做返回值;
  • 子程序返回值 (非标量):
    • 如果在子程序最后一句调用列表上下文,可以返回列表值;
#non-scalar return value
sub list_from_fred_to_barney{
	if ($fred < $barney) {
		$fred..$barney;
	} else {
    	reverse $fred..$barney;
    }
}
$fred = 11;
$barney = 6;
@c = &list_from_fred_to_barney;   #@c is (11 10 9 8 7 6) now

注意1.1中例:marine子程序执行的最后一次运算是print,它的返回值通常是 1,表示成功输出信息,但显然这不是我们想要的值,所以一定要注意子程序中最后执行的语句。

1.3 子程序的参数

  • Perl支持参数传入,要传递参数列表到子程序里,只要在子程序调用的后面加上括号内的列表表达式即可;
  • 列表传入子程序后,子程序自动将参数存入 @_,该变量在子程序执行期间有效,子程序通过访问这个数组,以判断参数的个数和参数值;
    • 传入的参数 > 子程序需要,后面的参数将被忽略;
    • 传入的参数 < 子程序需要,缺少的参数值被定为undef;
#列表传入,max比较传入的两个参数,返回值较大的那个
sub max {
	if($_[0] > $_[1]) {
		$_[0];
	} else {
		$_[1];
	}
}
&max(10,15);      # return 15
&max(10,15,27);   # return 15
  • 实际上,@_是子程序的私有变量。假如已经存在全局变量 @_,会不会出现问题呢?
    • 当然不会!
    • 子程序使用@_时,如果已经存在全局变量@_,则全局变量的值在调用前会被先存储起来,等待子程序结束后,全局变量@_恢复原来的值;
    • 因此,各种子程序可以不加担心的进行嵌套调用,递归调用时同样可以不考虑这个问题;
    • 回忆一下:foreach循环保存控制变量的机制类似,变量的值都是perl自动保存和恢复的。
1.3.1 变长参数列表
  • 在常见的Perl代码中,经常把更长的列表作为参数传递给子程序,Perl对传入的列表长度不做限制;
    • 我们可以在函数中设置检查;
    • 其实,我们更希望可以修改子程序,让其可以接受任意长度的列表;
#变长列表传入
sub max {
	if(@_ != 2) {
		print "WARNING! &max should get exactly two arguments!\n";
	}
	...
}

#update subroutine max
sub max {
	my ($max_so_far) = shift @_;
	foreach (@_) {
		if($_ > $max_so_far) {
			$max_so_far = $_;
		}
	}
	$max_so_far;
}
$maximum = &max(1,2,34,6,7);    #$maximum is 34 now
$max_num = &max(@num);          #when @num = (), shift @_ 返回undef, foreach 循环不执行,最终返回undef

2. 子程序中的变量

2.1 子程序中的私有变量

  • 在默认情况下,perl里面的所有变量都是全局变量,也就是说,在程序里的任何地方都可以访问他们,但是我们可以借助 my 操作符来定义私有变量;
#my lexical variable
sub max{
	my ($m,$n);
	($m,$n) = @_;     #可以合并为 my($m,$n) = @_;
	if ($m > $n)  { $m; } else { $n; }	 
}

2.2 用my声明的词法变量

  • 用 my 声明的词法变量不仅可以用在子程序中,可以以用在 if,while,foreach 的语句块内;
    • 如: foreach (1…0) { my ($square) = $_ * $_; } -> $square的作用域为foreach循环内部;
    • 如果变量的定义并未出现在任何语句块中,则这个变量对整个程序原文件都是私有的;
    • 这些私有变量的作用范围容易定位,如果出现调用问题,debug速度会提升;
  • my操作符不会改变变量赋值时的上下文
    • my ($num) = @_; #列表上下文,和 ($num) = @_; 相同, $num 为@_的第一个参数;
    • my $num = @_; #标量上下文,和 $num = @_; 相同,$num为@_中的参数个数;
  • my操作符不加括号时,只能用来声明单个变量
    • my $fred,$barney; #只声明了$fred;
    • my ($fred,$barney); #声明了 $fred 和 $barney;

2.3 持久化私有变量

  • 持久化私有变量:
    • 由关键字 state 声明;
    • state声明的变量,可以在函数被多次调用用保存上次的值 (静态变量?);
    • 其作用域同样限制在子程序内部,外部不能调用此私有变量;
#update sunroutine in 1.1
sub marine {
	state $n = 0;
	$n += 1;
	print "$n time call marine subroutine.\n";
}

#注意: v5.10中并不支持在列表上下文中初始化数组和哈希表类型的state变量
state @array = qw/a b c/;  #ERROR!!!

3. 子程序的中级用法

3.1 use strict 编译指令

  • 编译指令,是指提供给编译器的指令,他告诉编译器如何处理接下来的程序代码;
  • 如果希望perl严格要求自己的话,可以再最开始加上 use strict;编译指令;
  • 有无 use strict的对比:
    • 编写语句:$bam = 3; $ban += 1;
    • 无:Perl自动创建bam变量,自动创建ban变量,不给警告;
    • 有:Perl自动检查,产生了两个只使用一次的全局变量,发出警告;
    • 这时候Perl会报错说 ban 变量没有被声明,提示程序员修改;

3.2 return操作符

  • 如果希望子程序执行到某个条件就停止的话,可以使用 return 操作符
#return character
sub find_5 {
	foreach(@_) {
		if($_ == 5) {
			print "5 is in this array";
			return $_; 
		} 
	}
	print "5 is in this array";
	return 0;
}
$num = &find_5(1..8);

3.3 省略 & 字符

  • 如果Perl内置函数和子程序名称冲突,调用子程序时必须使用 & 字符
  • 如果Perl能够从语法上判断是子程序调用语句,调用子程序时可以省略 & 字符
    • 子程序定义在子程序调用之前;
    • 子程序调用时将列表放在圆括号中;如:$num = find_5(1…8);

4. 子程序签名(补充)

  • 到目前为止,我们知道子程序内部接受参数时,从@_中获取参数列表,然后复制给私有变量,如&max函数。
  • Perl 5.20中添加了子程序签名特性,目前还是实验特性。
  • 使用子程序签名之后,就可以把变量声明移到花括号外面,直接写在程序明后的括号中。
#my lexical variable
sub max{
	my ($m,$n);
	($m,$n) = @_;
	if ($m < $n)  { $m; } else { $n; }	 
}

#使用子程序签名
use v5.20;
use feature qw(signatures);
no warnings qw(experimental::signatures);

sub max($m,$n){
	if ( $m < $n) { $n; } else { $m; } 
}
  • 这时,Perl自动声明这两个变量为子程序的私有变量,运行效果基本相同;但之前可以给 &max 传递多个参数,不会报错,但是使用了子程序签名之后就会报错;
    • 提示: Too many arguments for subroutine.
  • 因此,子程序签名是会帮助检查参数数量的;
  • 如果希望可以传递任意长度的数组:
    • 在声明变量的时候,声明数组 (数组的大小是不会被限制的);sub max ($max_so_far, @rest) { … };
    • 在声明变量的时候,使用 @ 占位,表明参数数量不定; sub max ($max_so_far, @) { … };
  • 如果传入参数少于声明参数数量:
    • 在声明变量的时候,可以指定默认值; sub max ($fred = 0, $barney = 7) { … };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值