sub
关键字开头,表示声明一个子程序&SUB_NAME()
的方式调用SUB_NAME子程序,&
有时候能够省略,括号有时候也能够省略。具体的规则见后面sub mysub { $n += 1; print "\$n is: $n","\n"; } &mysub; print "\$n is: $n","\n";
sub mysub { $n += 2; print "hello world\n"; $n + 3; } $num = ⊂
这里的&sub
有返回值,它的返回值是最后执行的语句$n+3
,并将返回值赋值给$num
,因此$num
的值为5。html
若是把上面的print做为最后一句:python
sub mysub { $n += 2; $n + 3; # 这不是返回值 print "hello world\n"; # 这是返回值 } $num = ⊂
上面的print才是子程序的返回值,这个返回值是什么?这是一个输出语句,它的返回值为1,表示成功打印。这个返回值显然没什么用。因此,子程序最后执行的语句必定要当心检查。shell
那上面的$n+3
的结果是什么?它的上下文是void context,相加的结果会被丢弃。数组
子程序还能够返回列表。安全
($m,$n)=(3,5); sub mysub { $m..($n+1); } @arr=&mysub; print @arr; # 输出3456
return
子句来返回值。固然,若是这个返回语句是最后一行,就能够省略return# 返回一个偶数 $n=20; sub mysub { if ($n % 2 == 0){ return $n; } $n-1; # 等价于 return $n-1; } $oushu=&mysub; print $oushu,"\n";
Perl子程序除了能够直接操做全局变量,还能够传递参数。例如:函数
&mysub(arg1,arg2...); &mysub arg1,arg2...;
至于何时能够省略括号,后面再解释。测试
@_
中@_
是数组,就可使用$_[index]
的方式引用数组中的各元素,也就是子程序的各个参数@_
数组只在每一个子程序执行期间有效,每一个子程序的@_
都互不影响。子程序执行完成,@_
将复原为原来的值# 返回最大值 @_=qw(perl python shell); # 测试:先定义数组@_ sub mysub { if($_[0] > $_[1]){ $_[0]; }else{ $_[1]; } } $max = &mysub(10,20); print $max,"\n"; print @_; # 子程序执行完,@_复原为qw(perl python shell)
若是上面的子程序给的参数不是两个,而是3个或者1个(&mysub(10,20,30);
、&mysub(10);
)会如何?由于参数是存在数组中的,因此给的参数多了,子程序用不到它,因此忽略多出的参数,若是给的参数少了,那么缺乏的那些参数被引用时,值将是undef。code
因此,在逻辑上来讲,参数多少不会影响子程序的错误,但结果可能会受到一些影响。但能够在子程序中判断子程序的参数个数:htm
if(@_ != 2){ # 若是参数个数不是2个,就退出 return 1; }
这里的比较是标量上下文,@_
返回的是参数个数。blog
通常状况下,调用咱们自定义的子程序时,都使用&
符号,有时候还要带上括号传递参数。
&mysub1(); &mysub2; &mysub3 arg1,arg2; &mysub4(arg1,arg2);
但有时候,&
符号和括号是能够省略的。主要的规则是:
&
也能够不省略&
&
的状况比较少。基本上,只要子程序名称不和内置函数同名,或者有特殊需求时(如须要明确子程序的名称时,如defined(&mysub)
),均可以省略&
&
、有参数传递的状况下,省略括号&subname(arg1,arg2)
,即不省略&
和括号&subname
&
的调用方式是比较古老的行为,虽然安全。但直接使用括号调用也基本无差异,但却更现代,因此建议用func()的方式调用自定义的子程序sub mysub{ print @_,"\n"; } # 先定义了子程序 mysub; # 正常调用 mysub(); # 正常调用 mysub("hello","world3"); # 正常调用 mysub "hello","world4"; # 正常调用 &mysub; # 安全的调用 &mysub("hello","world6"); # 安全的调用 &mysub "hello","world7"; # 本调用错误,由于使用了&,且有参数
上面是先定义子程序,再调用子程序的。下面是先调用子程序,再定义子程序的。
mysub; # 本调用无括号,不报错,当作内置函数执行,但无此内置函数,因此忽略 mysub(); # 有括号,不报错 mysub("hello","world3"); # 有括号,不报错 mysub "hello","world4"; # 无括号,本调用错误 &mysub "hello","world7"; # 本调用错误 &mysub; # 安全的调用 &mysub("hello","world6"); # 安全的调用 sub mysub{ print @_,"HELLO","\n"; }
若是子程序名称和内置函数同名,则不安全的调用方式总会优先调用内置函数。
my关键字能够声明局部变量、局部数组。它能够用在任何类型的语句块内,而不限于sub子程序中。
sub mysub { my $a=0; # 一次只能声明一个局部目标 my $b; # 声明变量,初始undef my @arr; # 声明空数组 my($m,$n); # 一次能够声明多个局部目标 ($m,$n)=@_; # 将函数参数赋值给$m,$n my($x,$y) = @_; # 一步操做 } foreach my $var (@arr) { # 将控制变量定义为局部变量 my($sq) = $_ * $_; # 在foreach语句块内定义局部变量 }
在my定义局部变量的时候,须要注意列表上下文和标量上下文:
@_=qw(perl shell python); my $num = @_; # 标量上下文 my (@num) = @_; # 列表上下文 print $num,"\n"; # 返回3 print @num,"\n"; # 返回perlshellpython
在Perl中,除了my能够修饰做用域,还有local和our也能够修饰做用域,它们之间的区别参见:Perl的our、my、local的区别。
my关键字是让变量、数组、哈希私有化,state关键字则是让私有变量、数组、哈希持久化。注意两个关键字:私有,持久化。
使用state关键字声明、初始化的变量对外不可见,但对其所在子程序是持久的:每次调用子程序后的变量值都保存着,下次再调用子程序会继承这个值。
这个特性是perl 5.10版才引入的,因此必须加上use 5.010;
语句才能使用该功能。
use 5.010; $n=22; sub mysub { state $n += 1; print "Hello,$n\n"; } &mysub; # 输出Hello,1 print $n,"\n"; # 输出22 &mysub; # 输出Hello,2 print $n,"\n"; # 输出22
固然,若是在子程序中每次都用state将变量强制初始化,那么这个变量持久与否就无所谓了,这时用my关键字的效果是同样的。
use 5.010; sub mysub { state $n=0; print "hello,$n","\n"; } &mysub; &mysub; &mysub;
state除了能够初始化变量,还能够初始化数组和hash。但初始化数组和hash的时候有限制:不能在列表上下文初始化。
use 5.010; sub mysub { state $n; # 初始化为undef state @arr1; # 初始化为空列表() state @arr2 = qw(perl shell); # 错误,不能在列表上下文初始化 }
由于perl中支持先定义子程序再调用,也支持先调用再定义的方式。不一样的调用方式有可能会有区别。
例如:
#!/usr/bin/env perl -w use strict; # do_stuff(1); # (1).在定义的前面 { my $last = 1; sub do_stuff { my $arg = shift; print $arg + $last; } } do_stuff(1); # (2).在定义的后面
上面在不一样的位置调用子程序do_stuff(1)
,但只有第二种方式是正确的,第一种方式是错误的。
缘由在于my定义的变量是词法做用域变量,先不用管词法做用域是什么。只须要知道my定义的变量是在程序编译期间定义的好的,可是赋值操做是在程序执行期间进行的。而子程序sub的名称do_stuff是没法加my关键字的,因此perl中全部的子程序都是全局范围可调用的。子程序的调用是程序执行期间的。
因此上面的程序中,整个过程是先在编译期间定义好词法变量$last
(但未赋值初始化),子程序do_stuff。而后开始从程序头部往下执行:
当执行到(1)的位置处也就是调用子程序,这个子程序中引用了变量$last
,但$last
至今未赋值,因此会报变量未初始化的错误。
若是没有(1),那么从上往下执行将首先执行到my $last = 1
,这表示为已在编译期间定义好的变量赋值。而后再继续执行到(2)调用子程序,但子程序引用的$last
已经赋值初始化,因此一切正常。
在perl中的子程序是在编译期间定义好的,仍是执行期间临时去定义的,目前我我的还不是太肯定,按照perl的做用域规则,它应该是在执行期间临时去定义的。但不管如何,它先定义仍是后定义,都不影响对变量做用域的判断。