流程控制
最基礎的流程就是從開始到結束温赔,一行一行的執(zhí)行:
say 'At start';
say 'In middle';
say 'At end';
條件分支
if指令會在條件表達式為真時執(zhí)行相應的動作:
say 'Hello, Bob!' if $name eq 'Bob';
這個是后綴形式蛤奢,在執(zhí)行簡單表達式時非常有用。還有一種是當條件表達式為真時執(zhí)行塊的形式:
if ($name eq 'Bob')
{
say 'Hello, Bob!';
found_bob();
}
此時條件表達式的****圓括號不可省略陶贼,且要有塊的形式(那就是大括號也不能势》贰)。****
條件表達式可以由多項組成:
if ($name eq 'Bob' && not greeted_bob())
{
say 'Hello, Bob!';
found_bob();
}
使用后綴形式拜秧,添加括號增加可讀性:
greet_bob() if ($name eq 'Bob' && not greeted_bob());
unless指令的意思與if相反痹屹,就是當條件為假時執(zhí)行對應動作,它的用法和if一樣枉氮。
say "You're not Bob!" unless $name eq 'Bob';
unless (is_leap_year() and is_full_moon())
{
frolic();
gambol();
}
if和unless都支持else指令志衍。執(zhí)行條件與主句條件相反。
if ($name eq 'Bob')
{
say 'Hi, Bob!';
greet_user();
}
else
{
say "I don't know you.";
shun_user();
}
unless ($name eq 'Bob')
{
say "I don't know you.";
shun_user();
}
else
{
say 'Hi, Bob!';
greet_user();
}
unless與if表達的意思相反聊替,可以相互轉(zhuǎn)換楼肪,根據(jù)自己的喜好,挑個順手的用就好惹悄。
如果你有很多的條件要逐一比對春叫,你可以在if中使用elsif指令:
if ($name eq 'Bob')
{
say 'Hi, Bob!';
greet_user();
}
elsif ($name eq 'Jim')
{
say 'Hi, Jim!';
greet_user();
}
else
{
say "You're not my uncle.";
shun_user();
}
下面這個會報錯,沒有(else if)這種語法:
if ($name eq 'Rick')
{
say 'Hi, cousin!';
}
# warning; syntax error
else if ($name eq 'Kristen')
{
say 'Hi, cousin-in-law!';
}
三目操作符
三目操作符(? :)可以根據(jù)給定的條件選擇執(zhí)行表達式.條件表達式為真時執(zhí)行表達式1泣港,條件表達式為假時執(zhí)行表達式2:
條件表達式 ? 表達式1 : 表達式2
my $time_suffix = after_noon($time)
? 'afternoon'
: 'morning';
這里有個例子展示了三目操作符不僅能用于值還能用于變量:
push @{ rand() > 0.5 ? @red_team : @blue_team }, Player->new;
****短路****
Perl在遇到復雜的條件表達式時具有短路行為暂殖,原則就是:當Perl能確定整個多項表達式的真假時就不會繼續(xù)去計算每一個子項。
say 'Both true!' if ok( 1, 'subexpression one' )
&& ok( 1, 'subexpression two' );
done_testing();
ok 1 - subexpression one
ok 2 - subexpression two
Both true!
上例中2個子項都執(zhí)行了当纱,下面這個例子中只需要計算第一項就夠了:
say 'Both true!' if ok( 0, 'subexpression one' )
&& ok( 1, 'subexpression two' );
not ok 1 - subexpression one
邏輯運算中有個特征:與運算中呛每,有一項為假時就能確定整個值為假;或運算中坡氯,有一項為真就能確定整個值為真莉给。
條件指令的語境
條件指令:if毙石,unless,還有三元條件操作符提供的都是****布爾語境****颓遏。
比較操作符徐矩,如eq,==叁幢,ne滤灯,and, !=也都產(chǎn)生的是布爾值曼玩。
Perl沒有單獨的真值和單獨的假值鳞骤。任何數(shù)值為0的數(shù)字都是假,如0, 0.0, 0e0, 0x0黍判。字符串'0'和空字符''也是假值豫尽。但是字符串'0.0', '0e0'不是假值∏晏空列表和undef都是假值美旧。空數(shù)組和空哈希在標量環(huán)境中返回數(shù)字0贬墩,所以在布爾語境中也是假值榴嗅。數(shù)組中只要擁有一個元素(哪怕是undef),那么這個數(shù)組在布爾語境中也是真值陶舞。類似的嗽测,哈希中只要有一個元素,即使鍵和值是undef肿孵,也是真值唠粥。
循環(huán)
foreach (1 .. 10)
{
say "$_ * $_ = ", $_ * $_;
}
跟if和unless一樣,也支持后綴:
say "$_ * $_ = ", $_ * $_ for 1 .. 10;
也可以顯式使用自定義的變量:
for my $i (1 .. 10)
{
say "$i * $i = ", $i * $i;
}
注意:改變變量的值停做,會修改原始值:
my @nums = 1 .. 10;
$_ **= 2 for @nums;
#@nums數(shù)值變了
所以當修改常量時就會報錯:
$_++ and say for qw( Huex Dewex Louid );
****迭代和范圍界定****
循環(huán)中可能會出現(xiàn)這樣一個問題:變量在內(nèi)部嵌套中是可見的晤愧,所以當使用默認變量$_,并且未對它做保護時就會出問題雅宾。此類問題非常隱蔽:
for (@values) #默認使用$_
{
topic_mangler();
}
sub topic_mangler
{
s/foo/bar/; # $_繼續(xù)有效养涮,修改$_就修改連原始數(shù)組!
}
所以:使用自定義的有名字的變量總是一個更好的選擇眉抬。
****C風格循環(huán)****
my $i = 'pig';
for ($i = 0; $i <= 10; $i += 2)
{
say "$i * $i = ", $i * $i;
}
****while和until****
while贯吓,當條件為真時執(zhí)行,直到條件為假蜀变。until與while相反悄谐,條件假時執(zhí)行,直到條件為真库北。(可以互換爬舰,挑自己順手的用)
while (1) { ... } #無限循環(huán)
while (my $value = shift @values)
{
say $value;
}
此循環(huán)有個隱秘的問題:當元素值為假值時就會退出循環(huán)们陆,而并不一定是耗盡了整個數(shù)組。
do
{
say 'What is your name?';
my $name = <>;
chomp $name;
say "Hello, $name!" if $name;
} until (eof);
循環(huán)至少執(zhí)行一次情屹。
****循環(huán)嵌套****
循環(huán)嵌套就是循環(huán)內(nèi)有循環(huán):
for my $suit (@suits) {
for my $values (@card_values) { ... }
}
****循環(huán)控制****
next-立即進入下一循環(huán):
while (<$fh>)
{
next if /\A#/;
...
}
last-立即結束循環(huán)坪仇。
while (<$fh>)
{
next if /\A#/;
last if /\A__END__/; #看到文件結尾標志立即結束
...
}
redo-重新進入當前迭代(無需評估循環(huán)條件)。
while (<$fh>)
{
print;
redo; #不能這樣寫垃你,因為這樣會不停重復循環(huán)
... #這后面的不會被執(zhí)行到
}
循環(huán)嵌套時椅文,可能不容易讓人理清楚結構,這時可以使用標簽:
LINE:
while (<$fh>)
{
chomp;
PREFIX:
for my $prefix (@prefixes)
{
next LINE unless $prefix;
say "$prefix: $_";
# next PREFIX is implicit here
}
}
****continue語句****
continue的使用非常少見惜颇,使用時一般和while, until, when, for循環(huán)一同使用皆刺。它將始終被執(zhí)行之前的條件再次進行計算,就像C語言的一個for循環(huán)中的第三部分凌摄。
while ($i < 10 ) {
next unless $i % 2;
say $i;
}
continue {
say 'Continuing...';
$i++;
}
Continuing...
1
Continuing...
Continuing...
3
Continuing...
Continuing...
5
Continuing...
Continuing...
7
Continuing...
Continuing...
9
Continuing...
注意:如果因為last或者redo指令離開當前迭代羡蛾,那么continue 塊當次不會被執(zhí)行。
****switch****
該功能是實驗性的锨亏,暫不介紹痴怨。
****尾部調(diào)用****
當函數(shù)中最后一個表達式調(diào)用函數(shù)時就是尾部調(diào)用。被調(diào)用的函數(shù)返回值將成為主函數(shù)的返回值屯伞。
sub log_and_greet_person
{
my $name = shift;
log( "Greeting $name" );
return greet_person( $name );
}
標量
標量腿箩,一個單一的豪直、離散的值劣摇。標量是Perl的基本數(shù)據(jù)類型。它可以是一個字符串弓乙,一個整型數(shù)字末融,浮點數(shù)字,一個文件句柄暇韧,或者是一個引用——但肯定是一個單一的值勾习。標量變量可以是詞法作用域,包作用域懈玻,也可以是全局作用域巧婶。標量變量總是使用美元($)記號。
標量和類型
my $value;
$value = 123.456;
$value = 77;
$value = "I am Chuck's big toe.";
$value = Store::IceCream->new;
不同語境下會發(fā)生類型轉(zhuǎn)換涂乌,Perl中的數(shù)字和字符串可以根據(jù)語境自動轉(zhuǎn)換艺栈,比如將數(shù)字視為字符串:
my $zip_code = 97123; #數(shù)字
my $city_state_zip = 'Hillsboro, Oregon' . ' ' . $zip_code; #字符串
也可以對字符串使用++操作符:
my $call_sign = 'KBMIU';
my $next_sign = ++$call_sign; # 返回新值,KBMIV
my $curr_sign = $call_sign++; # 返回舊值湾盒,然后再更新
my $new_sign = $call_sign + 1; # 這個可與上面2個效果不一樣湿右,這個值是1
++操作符用在數(shù)字上的行為是加一罚勾;但用在字符串上的行為是:a到b吭狡,z到aa;ZZ9到AAA0划煮, ZZ09 到ZZ10,這樣增長缔俄。
引用類型也能進行轉(zhuǎn)換般此,在字符串語境下計算引用時牵现,引用會返回字符串铐懊;在數(shù)字語境下會返回數(shù)字:
my $authors = [qw( Pratchett Vinge Conway )];
my $stringy_ref = '' . $authors; #字符串
my $numeric_ref = 0 + $authors; #數(shù)字
數(shù)組
數(shù)組,Perl語言的內(nèi)置數(shù)據(jù)結構瞎疼,包含0個或多個標量值科乎。你可以通過索引訪問各個數(shù)組成員,并且可以隨意添加和刪除元素贼急,數(shù)組變大和縮小都是自動處理的。@記號表示一個數(shù)組太抓。
聲明一個數(shù)組:
my @items;
數(shù)組元素
使用標量記號($)來訪問一個數(shù)字元素:
# @cats表示一堆貓,現(xiàn)在要訪問第一貓
my $first_cat = $cats[0];
# 標量語境返回元素個數(shù)
my $num_cats = @cats;
# 也是標量語境
say 'I have ' . @cats . ' cats!';
# addition
my $num_animals = @cats + @dogs + @fish;
# 布爾語境
say 'Yep, a cat owner!' if @cats;
#元素索引從0開始
my $first_index = 0;
my $last_index = @cats - 1; # 或者 my $last_index = $#cats;
say "My first cat has an index of $first_index, "
. "and my last cat has an index of $last_index."
#還支持從最后面開始定位碴倾,-1是最后一個元素掉丽,-2是倒數(shù)第二個……,不過要注意數(shù)量要夠
my $last_cat = $cats[-1];
my $second_to_last_cat = $cats[-2];
數(shù)組賦值:
my @cats;
$cats[3] = 'Jack';
$cats[2] = 'Tuxedo';
$cats[0] = 'Daisy';
$cats[1] = 'Petunia';
$cats[4] = 'Brad';
$cats[5] = 'Choco';
my @cats = ( 'Daisy', 'Petunia', 'Tuxedo', ... );
數(shù)組操作
- push 往數(shù)組末尾追加元素捶障,一個或多個
- pop 從數(shù)組末尾彈出一個元素
my @meals;
# what is there to eat?
push @meals, qw( hamburgers pizza lasagna turnip );
# ... but your nephew hates vegetables
pop @meals;
- shift 從數(shù)組開頭彈出一個元素
- unshift 在數(shù)組開頭插入元素,一個或多個
# expand our culinary horizons
unshift @meals, qw( tofu spanakopita taquitos );
# rethink that whole soy idea
shift @meals;
- splice 可以刪除數(shù)組中某段元素担平,也可以往數(shù)組中覆蓋或插入元素
my ($winner, $runnerup) = splice @finalists, 0, 2;
# or
my $winner = shift @finalists;
my $runnerup = shift @finalists;
- each 迭代返回元素的索引和值
while (my ($position, $title) = each @bookshelf) {
say "#$position: $title";
}
數(shù)組切片
標量每次只能訪問數(shù)組中的單個元素锭部,而有個叫數(shù)組切片的結構可以讓你訪問數(shù)組中的一系列(0個或多個)元素。
我們已經(jīng)知道了空免,表示多個元素需要用到記號@:
my @youngest_cats = @cats[-1, -2];
my @oldest_cats = @cats[0 .. 2];
my @selected_cats = @cats[ @indexes ];
@users[ @replace_indices ] = @replace_users;
數(shù)組切片的索引為列表語境:
# function called in list context
my @hungry_cats = @cats[ get_cat_indices() ];
# single-element array slice; list context
@cats[-1] = get_more_cats();
# single-element array access; scalar context
$cats[-1] = get_more_cats();
****數(shù)組和語境****
在列表語境中,數(shù)組展平為列表扼菠。
my @cats = qw( Daisy Petunia Tuxedo Brad Jack Choco );
my @dogs = qw( Rodney Lucky Rosie );
take_pets_to_vet( @cats, @dogs );
sub take_pets_to_vet
{
# BUGGY: do not use!
my (@cats, @dogs) = @_;
...
}
扁平化有時也會造成混淆:
# creates a single array, not an array of arrays
my @numbers = (1 .. 10, (11 .. 20, (21 .. 30)));
# parentheses do not create lists
my @numbers = ( 1 .. 10, 11 .. 20, 21 .. 30 );
# creates a single array, not an array of arrays
my @numbers = 1 .. 30;
****數(shù)組插值****
數(shù)組在內(nèi)插到雙引號包圍的字符串中時,會返回這樣一個字符串:由$"的值將每個元素連接起來循榆。
$"的值默認是一個空格。
my @alphabet = 'a' .. 'z';
say "[@alphabet]";
[a b c d e f g h i j k l m
n o p q r s t u v w x y z]
自定義$" 以便輸出特定形式的結果:
local $" = ')(';
say "(@sweet_treats)";
(pie)(cake)(doughnuts)(cookies)(cinnamon roll)