您的位置:首页 > 其它

perl学习笔记-----------------------(4)

2017-04-22 00:00 211 查看
1.强制转换为标量Context

偶尔,你可能需要标量context 而Perl 期望的是列表。这种情况下,可以使用函数scalar。它不是一个真实的函数因为其仅

是告诉Perl 提供一个标量context:

@rocks = qw(talc quartz jade obsidian);
print “How many rocks do you have?\n”;
print “I have ”, @rocks, “rocks!\n”; #错误,输出rocks 的名字
print “I have ”, scalar @rocks, “rocks!\n”; #正确,输出其数字


奇怪的是,没有对应的函数能强制转换为列表context。但请相信我们,事实上你并不需要它。

2.在列表context 中,它将返回这个输入文件的所有剩余部分。而每一行将作为一个独立的元素,如下所示:

@lines = <STDIN>; #将输入读入列表context 中
当输入来源于一个文件时,它将读入文件的剩余部分。但如果输入来源于键盘,那文件结束符(end-of-file)是怎样输入的呢?

在Unix 或者类似的系统中,包括linux, Mac OS X,通常可以输入CTRL +D来表明输入已经结束。Perl 会忽略这个字符,

因此它将在屏幕上显示出来。在DOS/WINDOWS 系统中,使用CTRL +Z。

3.如果将chomp 应用于一个包含字符串的数组中,他将把这

个数组中每一个元素的换行符去掉,如下例所示:

@lines = <STDIN>; #读入所有的行
chomp = (@lines); #去掉所有的换行符
但更常见的做法是:

chomp (@lines = <STDIN>); #读入所有的行,不包括换行符


3.9 练习
1. [6] 写一个程序,将一些字符串(不同的行)读入一个列表中,逆向输出它。如果是从键盘输入的,那在Unix 系统中应当使用CTRL+D 表明end-of-file,在Windows 系统中使用CTRL+Z.


#!usr/bin/perl -w
print "Enter some lines,then press Ctrl-D:\n";
@lines=<STDIN>;
@reverse_lines=reverse @lines;
print @reverse_lines;
或者

#!usr/bin/perl-w
print "Enter some lines ,then press Ctrl-D:\n";
print reverse<STDIN>;


2. [12] 写一个程序,读入一串数字(一个数字一行),将和这些数字对应的人名(下面列出的)输出来。(将下面的人名列表写入代码中)。例如,当输入为1,2,4 和2,则输出的为fred, betty, dino, 和betty:fred betty barney dino Wilma pebbles bamm-bamm

#!usr/bin/perl -w
@names=qw/ fred betty barney dino Wilma pebbles bamm-bamm /
print "Enter some numbers from 1 to 7,one per line ,then press Ctrl-D:\n";
chomp(@numbers=<STDIN>);
foreach(@numbers){print "$numbers[$_ -1]\n"; }


3. [8]写一个程序,将一些字符串(在不同的行中)读入一个列表中。然后按ASCII 顺序将它们输出来。也就是说,当输入的字符串为fred, barney, wilma, betty,则输出为barney betty fred wilma。分别在一行或不同的行将之输出。
#!usr/bin/perl -w
chomp(@lines=<STDIN>);
@sorted=sort @lines;
print "@sorted \n";\\或让每行分开显示
print sort<STDIN>


4.要定义自己的子程序,使用关键字sub,子程序的名字(无&这个符号),组成子程序的缩进的代码块(花括号中),如:
◆恰当的说,花括号也属于块的一部分。Perl 不需要缩进块中的代码,但维护人员需要。因此请遵守这个规则。


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


5.子程序的定义可以在程序的任意位置,但具有如C 或者Pascal 背景的程序员通常将它们放在程序的开头。某些其它的程序员可能将它们放在结尾,以使程序的主要部分在开头出现。不需要在定义之前有任何声明。子程序的定义是全局的;没有某些强大的技巧,Perl 中没有私有子程序(private subroutines)◆。如果两个子程序有相同的名字,那后一个将覆盖前一个

6.调用子程序可以使用子程序的名字(带有&)来调用子程序◆:
◆通常有括号,即便参数为空。子程序将继承调用者的@_的值,这会马上讨论。因此不要在这里停止,否则程序可能和你预期的行为不同。


&marine; #输出Hello, sailor number 1!
&marine; #输出Hello, sailor number 2!
&marine; #输出Hello, sailor number 3!
&marine; #输出Hello, sailor number 4!
通常,我们说调用(invocation)是指调用子程序(call the subroutine)。

7.子程序可以被某个表达式调用,无论此表达式的值是否被利用

8.当Perl 遍历此子程序时,将会计算每一步的值。此子程序中最后计算的值将被返回。

例如,下面的子程序:

sub sum_of_fred_and_barney{
print “Hey, you called the sum_of_fred_and_barney suroutine!\n”;
$fred + $barney; #返回值
}


子程序中最后一个被计算的表达式为$fred + $barney,因此$fred 和$barney 的和将被返回。下面是一些调用代码:

$fred = 3;
$barney = 4;
$wilma = $sum_of_fred_and_barney; #$wilma 得到7
print “\$wilma is $wilma.\n”;
$betty = 3 * &sum_of_fred_and_barney; #$betty 得到21
print “\n$betty is $betty.\n”;


上述代码将得到下面的输出:

Hey, you call the sum_of_fred_and_barney subroutine!
$wilma is 7.
Hey, you call the sum_of_fred_and_barney subroutine!
$betty is 21.


在上述例子中,最后一个被计算的表达式不是$fred + $barney;而是print 语句。其返回值通常为1,意思是“print was

succfessful(打印成功)”

8.在Perl 中,会自动将此参数列表(此参数列表的另一个名字)自动存放在一个叫做@_的数组中。子程序可以访问次数组变量来确定此参数的个数以及其值。这也就是说此子程序参数的第一个值存放在$_[0]中,第二个存放在$_[1]。

9.@_是子程序的一个私有变量◆;如果有一个全局变量
@_ ,它将在此子程序调用前存储起来,当子程序调用完成后,其早

期的值会被重新赋还给@_◆。这意味着当将参数传递给子程序时不用担心它会影响此程序中其它子程序的@_这个变量的值。

嵌套的子程序调用时,@_的值和上述类似。甚至此子程序递归调用时,每一次调用将得到新的@_,因此子程序调用

时将得到其自身的参数列表。

9.默认情况下,Perl 中所有变量都是全局的;也就是说,这些变量可以在程序的任意部分使用。你也可以任意时候使用my

创建私有变量:

sub max {
my($m,$n); #新的,私有变量
($m,$n) = @_; #赋值
if($m > $n) {$m} else{$n}
}


10.在if 代码块内部,其语句没有分号。Perl 允许省略括号中最后一条语句的分号,在实际代码中,通常仅当此代码

块仅包含一条语句时才省略此分号。

11.my 操作符可以用在有括号的变量的列表中,因此,通常将上述两个语句如下书写:

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


12.在实际的Perl 代码中,传递给子程序的参数个数是没有限制的。

13.子程序可以容易的检测@_是否含有恰当的个数

14.现在重写&max,使它可以在任意参数个数下都能正常工作:

$maximum = &max(3,5,10,4,6);
sub max {
my($max_so_far) = shift @_;
foreach (@_){
if($_>$max_so_far){
$max_so_far=$_;
}
}
$max_so_far;
}
这段代码使用了一种叫做high-water mark 的算法:洪水之后,会在岸边留下痕迹。最高处的标记,表明了到达的最高水位。

在此程序中,$max_so_far 记录最高的水位。第一行中置$max_so_far 为3(第一个参数),它是从参数数组:@_中移出来的。

此时,@_变成了(5,10,4,6),因为3 已被移出。此时出现过的最大数为3。

现在,foreach 循环遍历@_剩下的值。循环中的控制变量是默认变量$_。(请记住,$_和@_没有任何关系;它们名字相同

完全是巧合)。第一次循环时,$_为5。if 测试语句中发现它比$max_so_far 大,因此$max_so_far 现在变成了5。

下一次循环中,$_为10。它是一个更大的值,此时$max_so_far 为10。

接着,$_为4。现在$_小于$max_so_far:10。因此,if 中的语句块被跳过。

接着,$_为6,基于同样的原因,if 语句块被跳过。这是最后一次循环。

现在,$max_so_far 的值将被返回。他为最大值:10。

15.空参数列表:子程序第一行将@_的第一个元素赋给$max_so_far。这不会有什么坏影响;数组为空,shift 操作返回undef 给$max_so_far。

现在进入foreach 循环体,由于为空,循环体一次都不执行。

现在,Perl 返回$max_so_far 的值undef。在某种意义下,这是正确的答案,因为空表中没有最大的元素。

当然,当调用此子程序时注意返回值可能为undef,或者保证调用的参数非空。

16.my 操作不会改变赋值参数的context:

my ($num) = @_; #列表context, 同($sum) = @_;
my $num = @_; #标量context,同$num = @_;


在第一个例子中,$num 得到第一个参数,因为其在列表context 中;第二个例子中,将得到参数的个数,因为是在标量context

中。

17.通常,将warning 打开会报告这样使用my,或者你自己调用1-800-LEXICAL-ABUSE 来报告。使用strict pragma(将在后面提及),将会

阻止这类错误的发生。

my $fred, $barney; #错误!没有定义$barney
my ($fred, $barney); #两个均定义了


18.当然,可以使用my 创建新的,私有数组◆:

my @phone_number;
如果新的变量没被赋值的话:标量变量会自动赋与undef,而数组变量会赋与空列表。

19.Perl 严格一些;那可以使用strict pragma。告诉Perl 进行更严格的语法检测,需要在程序顶端use strict(或者在任意块或者文件中,如果你需要在此部分使用它):

use strict; #迫使采用更严格的检测

20.如果程序长度大于一个屏幕,则需要使用use strict。

21.返回操作

返回操作将立刻的从子程序中返回一个值:

my@names = qw /fred barney betty dinoWilma pebbles bam-bamm/;
my $result = &which_element_is(“dino”, @names);
sub which_element_is{
my($what, @array) = @_;
foreach(0..$#array){ #@array 元素的索引
if($waht eq $array[$_]){
return $_; #找到既返回
}
}
-1; #没有找到元素(此处是可选的)
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: