Perl学习笔记04——子程序

▲说明

1.子程序的名字只能以字母、数字和下划线组成,同时不能以数字开头。

2.调用子程序可在其名字前加上与号(&),表示调用动作。

3.子程序名属于独立的名字空间,Perl不会把&fred$fred搞混,因为它们分属于不同的命名空间。

定义子程序

定义子程序的方法

先用关键字sub开头,再写上子程序名,然后写上花括号,封闭在花括号里的代码块就是子程序的主体。

sub marine{
    $n += 1;  #全局变量$n
    print "Hello, sailor number $n!
"; 
}

 NOTE

1.子程序可以被定义在程序中的任意位置,放在文件的开头、结尾都可以。

2.子程序的定义是全局的。

3.加入定义了两个重名的子程序,后面的子程序会覆盖前面的。

4.可以在子程序中使用任何全局变量。

调用子程序

子程序名前加上与号(&)就表示调用这个子程序,也叫呼叫子程序。

&marine;  #打印 Hello, sailor number 1!
&marine;  #打印 Hello, sailor number 2!
&marine;  #打印 Hello, sailor number 3!
&marine;  #打印 Hello, sailor number 4!

返回值

Perl中,所有子程序都有一个返回值,但并非所有返回值都有用,这要看具体进行的是什么操作。

子程序执行过程中最后一次运算的结果,不管它是什么,会被自动当作返回值。

sub sum_of_fred_and_barney{
    print "I love u more than yesterday, but less than tomorrow.
";
    $fred + $barney;  #这就是返回值
}

$fred = 3;
$barney = 4;
$wilma = &sum_of_fred_and_barney;  #$wilma为7
print "$wilma is $wilma.
";

$betty = 3 * &sum_of_fred_and_barney;  #$betty为21
print "$betty is $betty.
";

注意:

1.在子程序里添加额外的程序代码时,要注意检查最后执行的表达式是哪一个,确认它是你需要的返回值

sub sum_of_fred_and_barney{
    print "I love u more than yesterday, but less than tomorrow.
";
    $fred + $barney;
    print "Hey, I'm returning a value now!
";  #糟糕!
}

最后执行的语句不是加法运算,而是print语句,它的返回值通常是1,表示“成功输出信息”。

 2.$fred + $barney相加的结果被丢弃了,启用警告信息时,会提示void context(空上下文),表示运算结果未被使用,既没有存储到变量里,也没有被任何函数使用。

 3.“最后执行的表达式”的准确含义就是最后执行的表达式,而非程序的最后一行代码。

参数

传递参数列表到子程序,在子程序调用的后面加上括在括号内的列表表达式即可。

$n = &max(10,15);  #包含两个参数的子程序调用

Perl会自动将参数列表化名为特殊的数组变量@_,该列表在子程序执行期间有效。

第一个参数存储在$_[0],第二个参数存储在$_[1],依此类推。

sub max{
    if($_[0] > $_[1]){
        $_[0];
    }else{
        $_[1];
    }
}

缺点:

1.一堆下标,程序不雅观。

2.不提示接收几个参数。

@_变量是子程序的私有变量,加入已经有了全局变量@_,则该变量在子程序调用前会先被存起来,并在子程序返回时恢复原本的值。

子程序中的私有变量

可以使用my 操作符来创建私有变量,我们称之为词法变量

my ($m, $n) = @_;

变长参数列表

把长度不限的列表作为参数传递给子程序,解决办法:

1.检查@_数组的长度来判断参数个数是否符合预期

sub max{
    if(@_!=2){
        ...
    }
}

2.让子程序自动适应任意数目的参数

改进版的&max子程序:

$max_num = &max(3,5,10,4,6);
sub max{
    my $max_so_far = shift @_;
    foreach (@_){
        if($_ > $max_so_far){
            $max_so_far = $_;
        }
    }
    $max_so_far;
}

my声明的词法变量

词法变量可以用在任何语句块内,并不仅限于子程序的语句块;

1.ifwhileforeach内使用词法变量

2.foreach的控制变量也可以声明为词法变量

foreach my $rock(qw/bedrock slate lava/){
 ...
}

注意:

1.词法变量的作用域受限于定义它的最内层语句块内,或文件内,只有语句块的代码才能使用这个词法变量。

2.my操作符不会更改变量赋值时的上下文。

my ($num) = @_;  #列表上下文
my $num = @_;  #标量上下文

3.my操作符不加括号时,只能用来声明靠近的单个词法变量。

my $fred, $barney;  #错,没声明$barney
my ($fred, $barney);  #两个都声明了

4.最好对每个新变量都使用my声明,让它保持在自己所在的词法作用域内。

5.词法变量无法存续,语句块一结束,它的值就会被抛弃。

use strict编译指令

use strict编译指令用于告诉Perl愿意接受更严格是限制,可以放在程序开头,或是任何需要强制使用约束规则的语句块或文件内。

Perl 5.12开始,如果使用编译指令使用最低Perl版本号的话,就相当于隐式使用约束指令。

use v5,12;  #自动加载use strict编译指令

此限制只适用于创建新的变量,Perl的内置变量(比如$_@_)则完全不用事先声明。

return操作符

作用:立即停止运行并从子程序内返回某个值。

my @names = qw/ fred barney betty dino wilma pebbles bamm-bamm /;
my $result = &which_element_is("dino", @names);

sub which_element_is{
    my($what,@array) = @_;
    foreach(0..$#array){  #数组中所有元素的索引
        if($what eq $array[$_]){
            return $_;  #一发现就提前返回
        }
    }
    -1;  #表示没找到符合条件的元素(可以省略return)
}

NOTE

1.return最常见的用法:立即返回某个值,而不再执行子程序的其余部分。

2.最后一行写成return -1也行,读起来更明朗,但因为是最后一行,可以省略return

省略与号(&

1.Perl通过语法规则判断它只能是子程序调用,可以省略与号。

比如:将参数列表放进括号里,它就一定是子程序调用

my @cards = shuffle(@deck_of_cards); 

注意:

假如这个子程序和Perl内置函数同名,为避免歧义,就必须使用与号调用。所以只能在没有同名内置函数的情况下省略与号。

2.如果Perl的内部编译器已经见过子程序的定义,可以省略与号,并且参数列表两边的括号都可以不写。

sub division{
    $_[0]] / $_[1];
}
my $quotient = division 355, 113;

非标量返回值

子程序不仅可以返回标量值,如果在列表上下文中调用它,还可以返回列表值。

@c = &list_from_fred_to_barney;

持久化私有变量

在子程序中用my操作符可以创建私有变量,但每次调用子程序时,这个私有变量都会被重新定义。因为词法变量无法存续,语句块一结束,它的值就会被抛弃。用state操作符声明的变量可以在子程序的多次调用期间保留之前的值,而其作用域仍局限在子程序内部。

state是从Perl 5.10开始引入的。

原文地址:https://www.cnblogs.com/yd-yfb/p/13943696.html