Perl的子程序

子程序(subroutine)

  • perl中的子程序其实就是自定义函数。它使用sub关键字开头,表示声明一个子程序
  • 子程序名称有独立的名称空间,不会和其它名称冲突
  • Perl中的子程序中可以定义、引用、修改全局变量,这和几乎所有的语言都不同。当然,也可以定义局部变量
  • perl中使用&SUB_NAME()的方式调用SUB_NAME子程序,&有时候可以省略,括号有时候也可以省略。具体的规则见后面
sub mysub {
    $n += 1;
    print "\$n is: $n","\n";
}
&mysub;
print "\$n is: $n","\n";
  • perl的子程序最后一个执行的语句的结果或返回值就是子程序的返回值(是最后一个执行的语句,不是最后一行语句)。所以子程序总会有返回值,但返回值并不总是有用的返回值
sub mysub {
    $n += 2;
    print "hello world\n";
    $n + 3;
}
$num = ⊂

这里的&sub有返回值,它的返回值是最后执行的语句$n+3,并将返回值赋值给$num,所以$num的值为5。

如果把上面的print作为最后一句:

sub mysub {
    $n += 2;
    $n + 3;                 # 这不是返回值
    print "hello world\n";  # 这是返回值
}
$num = ⊂

上面的print才是子程序的返回值,这个返回值是什么?这是一个输出语句,它的返回值为1,表示成功打印。这个返回值显然没什么用。所以,子程序最后执行的语句一定要小心检查。

那上面的$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。

所以,在逻辑上来说,参数多少不会影响子程序的错误,但结果可能会受到一些影响。但可以在子程序中判断子程序的参数个数:

if(@_ != 2){     # 如果参数个数不是2个,就退出
    return 1;
}

这里的比较是标量上下文,@_返回的是参数个数。

调用子程序的几种方式分析

一般情况下,调用我们自定义的子程序时,都使用&符号,有时候还要带上括号传递参数。

&mysub1();
&mysub2;
&mysub3 arg1,arg2;
&mysub4(arg1,arg2);

但有时候,&符号和括号是可以省略的。主要的规则是:

  • 只有子程序定义语句在子程序调用语句前面,才可以省略括号
  • 当使用了括号,perl已经知道这就是一个子程序调用,这时可以省略&也可以不省略&
  • 不能省略&的情况比较少。基本上,只要子程序名称不和内置函数同名,或者有特殊需求时(如需要明确子程序的名称时,如defined(&mysub)),都可以省略&
  • 不能在使用了&、有参数传递的情况下,省略括号
  • 最安全、最保险的调用方式是:
    • 有参数时:&subname(arg1,arg2),即不省略&和括号
    • 无参数时:&subname
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关键字

my关键字可以声明局部变量、局部数组。它可以用在任何类型的语句块内,而不限于sub子程序中。

sub mysub {
    my $a=0;         # 一次只能声明一个局部目标
    my $b;           # 声明变量,初始undef
    my @arr;         # 声明空数组
    my($m,$n);       # 一次可以声明多个局部目标
    ($m,$n)[email protected]_;      # 将函数参数赋值给$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

state关键字

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);  # 错误,不能在列表上下文初始化
}

原文地址:https://www.cnblogs.com/f-ck-need-u/p/9512313.html

时间: 2024-10-07 20:18:01

Perl的子程序的相关文章

Perl学习笔记(四)--子程序

定义子程序: 要定义自己的子程序,可使用关键字sub,子程序名(不包含与号)以及用花括号封闭起的代码块,例如: 1 sub marine{ 2 $n +=1; #全局变量 $n 3 Print “Hello,sailor number $n \n”; 4 } 子程序不需要事先声明 子程序的定义是全局的,不存在私有子程序 假如定义两个重名的子程序,后面的子程序会覆盖掉前面的那个 调用子程序 1 &marine; 返回值 子程序中最后一次运算的结果都会被自动当成子程序的返回值 参数 要传递参数列表到

Perl 学习笔记-子程序

1.定义子程序 使用sub关键字定义 ;   子程序名和标识符同要求, 但是有的特殊的可以用 &符号;  子程序是全局的, 不需要再使用前声明;  重名函数后者覆盖前者. sub roger{ $n += 1; #全局变量$n print "Hello , sailor number $n!\n"; } &roger # 前面加&来调用, 不过没加好像也能调用. 返回值: 在子程序执行过程中会不断运算, 而最后一次运算的结果(不管是什么)都会被当成子程序的返回值

perl学习之子程序

一.定义子程序即执行一个特殊任务的一段分离的代码,它可以使减少重复代码且使程序易读.PERL中,子程序可以出现在程序的任何地方.定义方法为:sub subroutine{statements;}二.调用调用方法如下:1.用&调用&subname;...sub subname{...}2.先定义后调用 ,可以省略&符号sub subname{...}...subname;3.前向引用 ,先定义子程序名,后面再定义子程序体sub subname;...subname;...sub su

Perl子程序引用和匿名子程序

子程序也有引用,也有匿名子程序.假设你已经具备了数组.hash的引用知识,所以这里简单介绍一下. $ref_sub = \&mysub; # 子程序引用,&符号必须不能少 &{$ref_sub}(ARGS) # 解除子程序引用,传递参数ARGS &$ref_sub(ARGS) # 解除子程序引用 $ref_sub->(ARGS) # 解除子程序引用 $ref_sub->() # 传递空参数 sub {...}; # 定义匿名子程序,sub后面没有名称 $ref_

perl语言入门总结-第4章-子程序

子程序定义和返回值 sub sum{ print "调用了子程序\n"; $a + $b; #后一行为返回值 } $a=1; $b=33; $s =∑ #34 调用子程序 子程序中的参数,参数固定(下面例子只能2参数),程序第一个参数为$_[0],第二个为$[1],依次类推 sub max { if($_[0] > $_[1] ){ $_[0]; }else{ $_[1]; } } $n = & max(10,15); #结果为15 子程序中私有变量 sub max {

Perl语言入门(中文版)(第6版) 东南大学出版社

第一章简介 问题与答案 这本书适合你吗? 为何有这么多的脚注? 关于习题和解答? 习题前标的数字是什么意思? 如果我是Perl讲师? “Perl”这个词表示什么意思? Larry为什么要创造Perl? Larry干吗不用其他语言? Perl算容易,还是算难? Perl怎么会这么流行? 现在的Perl发展得怎么样了? 哪些事情最适合用Perl来做? 哪些事情不适合用Perl来做? 如何取得Perl? CPAN是什么? 如何得到Perl的技术支持? 还有别的技术支持方式吗? 如果发现Perl有bug

Perl 最佳实践(节选) --- 17

第十七章:模块 贰壹柒. 先设计模块的接口. 贰壹捌. 把原有代码变成inline. 把重复的代码放到子程序. 把重复的子程序放到模块. 贰壹玖. 使用三部分式的版本编号. 贰贰零. 程序化地实施你的版本需求. 贰贰壹. 明智地导出且只在可能场合有请求时才导出. 贰贰贰. 考虑以声明方式导出. 贰贰叁. 不要把变量变成模块接口的一部分. 贰贰肆. 自动建立新模块框架. 贰贰伍. 尽可能使用核心模块. 贰贰陆. 可行时就使用CPAN模块. 第十八章:测试和调试 贰贰柒. 先写测试案例. 贰贰捌.

Perl OOP

1. 模块/类(包) 创建一个名为Apple.pm的包文件(扩展名pm是包的缺省扩展名,意为Perl Module). 一个模块就是一个类(包). 2. new方法 new()方法是创建对象时必须被调用的,它是对象的构造函数. sub new { my $class = shift; my $this = {}; bless $this, $class; return $this; } this={}创建一个没有键/值对的哈希引用,返回值被赋给局域变量this. bless()函数将类名与引用相

perl学习之:函数总结

一.进程处理函数 1.进程启动函数 函数名 eval 调用语法 eval(string) 解说 将string看作Perl语句执行.正确执行后,系统变量[email protected]为空串,如果有错误,[email protected]中为错误信息. 例子 $print = "print (\"hello,world\\n\");";eval ($print); 结果输出 hello, world 函数名 system 调用语法 system(list) 解说