Learning Perl 2
1.子程序
?
1).創(chuàng)建子程序:使用關(guān)鍵字sub
sub marine {
print "Hello, world\n";
}
? ? calling subroutines,使用&號(hào)
&marine
(2).返回值:所有的子程序最后一個(gè)表達(dá)式的運(yùn)算結(jié)果都當(dāng)作返回值。所以子程序只有“”有用返回值“和無(wú)用返回值之分。所以讓一個(gè)類(lèi)似print的函數(shù)的結(jié)果來(lái)充當(dāng)返回值十分糟糕。比較合適的是最后一行有個(gè)if分支。
(3).參數(shù)
調(diào)用的時(shí)候加上列表表達(dá)式就行。例如&max(10, 15)。多余的變量都會(huì)被忽略,超過(guò)數(shù)組@_邊界的變量將會(huì)是undef。
Perl在子程序中用@_數(shù)組存儲(chǔ)參數(shù)。第一個(gè)參數(shù)是$_[0],第二哥存儲(chǔ)在$_[1]...
注意:這些變量?jī)H是數(shù)組@_的一部分,與標(biāo)量$_無(wú)關(guān)。這和任意變量$arr與@arr,$arr[0]無(wú)關(guān)的道理一樣。
sub max {
if($_[0] > $_[1]) {
$_[0];
} else {
$_[1];
}
}
@_是子程序的私有變量,如果有了一個(gè)全局變量@_,調(diào)用前會(huì)先被存起來(lái),并在子程序返回時(shí)恢復(fù)原本的值。
?
?
(4).Perl子程序的參數(shù)的傳遞是按引用傳。
#!/usr/bin/perl -w sub marine{ $_[0]="sub1"; $_[1]="sub2"; } $m="out1"; $n="out2"; print marine($m,$n)."\n"; print "$m\n$n"; 則會(huì)輸出 sub2 sub1 sub2 (5).由于perl的子程序參數(shù)是可變長(zhǎng)度的參數(shù)列表,可以用if來(lái)檢查 if(@_ != 2) { print "WARNING, this subroutine should get exactly two parameters!\n" } 塊的最后一條語(yǔ)句可以省略;號(hào)。無(wú)論在控制結(jié)構(gòu)的塊還是在子程序的塊中。 (6).return $_;立即返回某個(gè)值。 (7).何時(shí)可以省略調(diào)用子程序時(shí)的&:當(dāng)定義在調(diào)用之前,或者用()來(lái)傳遞參數(shù)時(shí)就可以省略& (8).返回非標(biāo)量值,最后一行為列表即可 sub marine{ #... reverse 1..10; } (9).采用高水位標(biāo)記算法來(lái)處理任意數(shù)量參數(shù)的max print &max(3,5,6,1,2,12); #或者直接傳入一個(gè)列表 #@numbers=(3,5,6,1,2,12); #print &max(@numbers); sub max { my($max_so_far)=shift @_; foreach (@_) { if($_ > $max_so_far) { $max_so_far=$_ } } $max_so_far } 2.perl范圍聲明 our,"把名字限于某個(gè)范圍“,其實(shí)就是明確聲明一個(gè)"全局變量",雖然是在某個(gè)模塊或者函數(shù)里面定義的,外面的也可以訪問(wèn),如果已經(jīng)聲明過(guò)了,再次用"our",表示此處用的是全局的那個(gè),不是同名的私有或者局部變量 our $PROGRAM_NAME = "waiter"; { my ?$PROGRAM_NAME = "something"; our $PROGRAM_NAME = "server"; #這里的our和外面的相同,和前句不同。 # 這里調(diào)用的代碼看到的是"server" } # 這里執(zhí)行的代碼看到的仍然是"server". my ,"把名字和值都限于限于某個(gè)范圍",簡(jiǎn)單說(shuō),就是只能本層模塊或者函數(shù)可以看到這個(gè)變量,高一層的或者低一層的都看不到的。 sub greeting1{ my ($hello) = "How are you do?"; greeting2(); }? sub greeting2{ print "$hello\n"; } $hello = "How are you doing?"; greeting2(); greeting1(); greeting2(); 運(yùn)行結(jié)果: How are you doing? How are you doing? How are you doing? -------------------------- 一個(gè) How are you do? 都沒(méi)有,在greeting1中call greeting2時(shí),greeting2看不到greeting1的私有 $hello變量,只能看到外面的全局變量$hello local,"把值局限于某個(gè)范圍",也有叫"動(dòng)態(tài)詞法范圍",有點(diǎn)不好懂。我的理解,就是本層和本層下層的函數(shù)可以看到本層的變量,但是本層上一層的不可以。到底范圍是多少,不僅取決于本層的函數(shù),還要看下一層的程序長(zhǎng)度和深度,所以叫"動(dòng)態(tài)范圍"。 sub greeting1{ local ($hello) = "How are you do?"; greeting2(); } sub greeting2{ print "$hello\n"; } $hello = "How are you doing?"; greeting2(); greeting1(); greeting2(); 運(yùn)行結(jié)果: How are you doing? How are you do? How are you doing? ----------------------- 跟用 my 時(shí)不一樣了吧? 此時(shí)在greeting1調(diào)用greeting2時(shí),greeting2可以看到greeting1的局部變量$hello,外部的全局變量當(dāng)然就隱藏了。 范圍操作符不會(huì)改變變量賦值時(shí)的上下文。 例如 my($num)=@_; #列表上下文,等同于($num)=@_,$num是第一個(gè)元素的值 my $num=@_; #標(biāo)量上下文,等同于$num=@_,$num是列表的長(zhǎng)度 3. 使用use strict;強(qiáng)制使用一些良好的程序規(guī)范,例如不能操作未初始化的變量。可以有效防止變量名打錯(cuò)的情況。 4. 鉆石操作符 鉆石操作符<>是perl的讀取文件(文件名通過(guò)參數(shù)傳入,即@ARGV數(shù)組。如果@ARGV為空,則改用標(biāo)準(zhǔn)輸入流)每一行的操作符,讓perl程序也能像cat,sed等應(yīng)用程序直接處理文本文件。是一個(gè)整行輸入操作符的特例。 #!/usr/bin/perl -w while (defined ($line=<>)){ chomp ($line); print "$line\n"; } 或者簡(jiǎn)寫(xiě)成 while (<>) { chomp; print "$_\n"; } print <> ; ? cat 的perl實(shí)現(xiàn), print sort <> ; sort的perl實(shí)現(xiàn) <>的另一個(gè)例子,通過(guò)打開(kāi)的文件描述符 open(HANDLE,"c:/test.txt") ? or ? die ? "文件不能打開(kāi)"; ? ? while ? (<HANDLE>) ? ? ? ? ? ? #注:這就是對(duì)文件句柄讀取一行并存入變量 ? $_ ?? { ?? print; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #注:打印變量 ? $_ ?? } 5.輸出至標(biāo)準(zhǔn)輸出 print 注意:print (2+3)*4;會(huì)打印5,然后print的返回值1(成功)會(huì)被乘以4. 小心這種帶括號(hào)的操作符用法。 printf和C語(yǔ)言的printf類(lèi)似,%g是輸出恰當(dāng)?shù)臄?shù)值形式。自動(dòng)輸出整數(shù),浮點(diǎn)數(shù)和指數(shù)形式。例如5/2, 51**17會(huì)輸出2.5,1.0683e+29 生成格式字符串 my @items=qw(wilma dino pebbles) my $format="The items are:\n".("%10s\n" x @items) #使用x來(lái)復(fù)制字符串,@items為3,即“%10s\n”三遍 printf $format, @items 6.文件句柄 (1).打開(kāi)文件句柄 通常文件句柄用大寫(xiě)標(biāo)識(shí)。 Perl提供3種文件句柄:STDIN STDOUT STDERR由Perl的父進(jìn)程(可能是Shell)提供。當(dāng)使用其他的文件句柄時(shí),使用open操作符告訴Perl。 例如: open CONFIG,"dino" open CONFIG,"<dino" #同上即默認(rèn)行為,表示這個(gè)文件是提供輸入數(shù)據(jù)的。不能創(chuàng)建則返回失敗0 open BEDROCK,">fred" #如果已經(jīng)有一個(gè)文件存在,則清楚原有內(nèi)容并以新內(nèi)容取代之 open LOG,">>LogFile" #如果不存在,則創(chuàng)建。如果存在,則追加 檢測(cè)文件句柄的有效性 my $success=open LOG,“>>logfile” unless ($success) { #open失敗 } 比如可以直接使用die中止運(yùn)行或者warning送出警告信息。perl程序的exit status:0成功,1語(yǔ)法錯(cuò)誤,2處理某程序發(fā)生錯(cuò)誤,3可能找不到某個(gè)細(xì)節(jié)配置文件等 if(!open LOG, ">>logfile") { warning "can not create file" } if(@ARGV < 2) die "Not enough arguments.\n" 另:open CONFIG, "logfile" or die "not such file"; 關(guān)閉文件描述符: close LOG (2).使用文件句柄 print LOG “...”; printf STDERR "..."; open PASSWD, "/etc/passwd" or die "cannot open passwd file" while (<PASSWD>) { chomp; ...... } 或者放到列表里 open PASSWD, '</etc/passwd'; @lines = <PASSWD>; $line=shift @lines; #print $line,"\n"; foreach $temp (@lines) { print $temp; } (3).用select改變默認(rèn)的輸出文件句柄 select LOG; print “<INFO>, ....”; #就會(huì)輸出到文件句柄LOG中而不是STDOUT select STDOUT; 默認(rèn)的情況,寫(xiě)出的文件都會(huì)經(jīng)過(guò)緩沖處理。只要將變量$|設(shè)置為1,就會(huì)在每次輸出操作后,立即清除緩沖區(qū)(flush) (4).重新打開(kāi)標(biāo)準(zhǔn)文件句柄 open STDERR, “>>/home/luffy/.error.log” #die和warn的信息會(huì)輸送到STDERR中(默認(rèn)是屏幕) 7.散列 (1).哈希是一種數(shù)據(jù)結(jié)構(gòu),類(lèi)似數(shù)組。但是不像數(shù)組以數(shù)字下標(biāo)進(jìn)行檢索,而是以檢索的鍵(即唯一的字符串標(biāo)識(shí))進(jìn)行檢索。哈希相當(dāng)于一些鍵/值隊(duì)的集合,沒(méi)有順序。 鍵一定要是字符串,如果以50/20為鍵,則會(huì)被轉(zhuǎn)換為一個(gè)含有三個(gè)字符的字符串”2.5”. 哈希沒(méi)有大小上限,可以是任意大小。 相對(duì)于其他腳本語(yǔ)言的哈希(如awk),Perl的哈希不會(huì)因?yàn)樽兇蠖a(chǎn)生性能問(wèn)題。 哈希的值可以是數(shù)字,字符串,undef或者這些類(lèi)型的組合。 哈希中的元素,賦值時(shí)會(huì)自動(dòng)增加。 當(dāng)鍵的字符串嚴(yán)格符合變量定義要求,或者定義時(shí)使用=>來(lái)定義。就可以免去鍵的引號(hào)。例如$family_name{fred}; 例如: $family_name{“fred”}=”flintstone”; foreach $person (qw <barney fred>) { print “I‘ve heard of person $person $family_name{$person}” } (2).引用整個(gè)哈希,用%號(hào) %myhash=("abc",1,"bcd",2,"cde",3); #以鍵,值,鍵,值,鍵,值存儲(chǔ)為hash %myhash=(%myhash,"def",4); %myhash=( "abc"=>1, "bcd"=>2, "cde"=>3 ); @myarr=%myhash; #展開(kāi)為列表 %new_hash=%myhash; #哈希的賦值,注意這一行代碼會(huì)讓%myhash展開(kāi)為列表,然后再?gòu)?fù)制給%new_hash %new_hash=reverse %myhash; #同上,先展開(kāi)為列表再做reverse運(yùn)算。注意reverse操作不僅會(huì)使位置倒置,而且會(huì)使鍵/值互換 #這里注意一點(diǎn):由于hash中不能有重復(fù)的鍵。如果展開(kāi)的列表后面有重復(fù)的鍵,它的值會(huì)覆蓋掉前面的! (3). 散列函數(shù) my $k = keys %myhash; my $v = values %myhash; if (%hash) { #直接作為bool判斷 print “exists one kv pair”; } 對(duì)散列進(jìn)行迭代,可以使用each函數(shù)獲得下一組kv隊(duì),直到所有元素被訪問(wèn)到。例如 while(($key,$value)=each %myhash) { #each會(huì)返回包含一組鍵值對(duì)的列表,直到each返回空列表,$key和$value都會(huì)是undef print "$key=>$value"."\n"; } if(exists $books{"Thinking in Java"}) #exists函數(shù)! print "the book exists"; delete $book{"thinking in Java"} #delete函數(shù)! } 哈希元素的內(nèi)插,需要用循環(huán)來(lái)以此輸出。不支持整個(gè)哈希列表的內(nèi)插 my %hash = ("a"=>1, "b"=>2, "c"=>3, "d"=>4); foreach $key (sort keys %hash) { print "$key => $hash{$key}\n"; } 參考:perl范圍聲明our,my,local ? ? ?http://blogold.chinaunix.net/u1/51156/showart_441696.html Textbook:learning perl?
轉(zhuǎn)載于:https://blog.51cto.com/aboocool/586595
總結(jié)
以上是生活随笔為你收集整理的Learning Perl 2的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。