一、數據類型(Data Type)
學習一門編程語言,首先需要了解的就是這門編程語言有那幾種數據類型。Perl的數據類型大致可以分為四類:Scalar(標量)、Array(數組)、Hash(哈稀)以及Reference(引用)。看起來,四種數據類型似乎顯得先天不足,但用起來卻已綽綽有余。
1、Scalar(標量)
標量是Perl中最簡單的一種數據類型,也是構成其它三個數據類型的基石。標量變量可以代表一個字符、字符串以及數字(整數或浮點數)。變量變量以$開頭。如下:
1 my $x = "abcd"; 2 my $y = 999999; 3 my $z = 1.0001;
在Perl中,字符串型標量和數值型標量並沒有顯著的差別。實際上,在特定情況下,Perl會根據需要在字符串和數值之間進行轉換。是否發生轉化由操作符決定,若操作符需要的是一個字符串而提供的操作數卻是一個數值,或者反過來,操作符需要的是數值而提供的操作數卻是字符串,那么轉化將發生。
對數值進行運算的操作符(比如加減乘除運算)如果遇到字符串類型的操作數,Perl會自動將字符串轉化成等效的十進制浮點數進行運算。比如,12 * "f10d"會得到0,而12 * "10fd"卻會得到120。
同樣的,對字符串進行操作的操作符遇到數值型的操作數時,給數值就被轉換成相同的字符串。比如"xyz" . 99會得到"xyz99"。
2、Array(數組)和List(列表)
列表可以看成是由一系列標量的有序集合,而數組就是用來存儲列表的變量,數組變量以@開頭。如下:
1 my @arr = (17, "hello", 13.78); 2 my @arr = (length("hello"), "xy" . "z"); 3 my @arr = ($var, 0.09*55);
等號左邊是列表,右邊是數組變量,數組中存儲着列表。當然,列表不止這一種表示方式。需要注意的有兩點:
(1)Perl中數組變量創建時初始值為空列表()
(2)Perl中數組變量和標量標量處於不同的命名空間,所以同一個變量名可以同時用作數組變量和標量變量而不用擔心命名沖突。
數組中元素可以通過下標操作符[]表示,第一個元素的下標為0,最后一個元素的下標為-1。試圖訪問不存在的數組元素將得到undef,如果給超出數組大小之外的元素賦值,則Perl數組將自動增長,原來沒有的元素的值為undef。如下:
my @arr = (1, 2, 3); my $var = $arr[5]; # $var will get undef
$arr[5] = 8; # @arr changes to (1,2,3,undef,undef,8)
需要注意的是,當你需要提取某個數組元素時,用的是$開頭,而非@,這很容易理解:數組的元素是一個標量值。
3、Hash(哈稀)和散列
哈稀是一種數據結構,它和數組的區別在於:不像數組以下標來檢索元素,哈稀使用鍵來檢索元素。可以這樣理解:哈稀結構中每一個元素都有一個鍵和一個值,鍵必須唯一,可以通過鍵來映射到值。如下所示:
my %hash = (1 => "fred", 2.5 => 1, "fred" => 2.5);
其中,符號"=>"在Perl中被戲稱為胖箭頭,它很好的展示了哈稀結構中鍵與值的映射關系:胖箭頭左邊的1、2.5以及"fred"是鍵,胖箭頭右邊的"fred"、1、2.5就是各個鍵對應的值。任何的標量元素都可以作為hash結構中的鍵和值,上面的哈稀結構三對鍵值對就形成了一個循環。
關於胖箭頭,需要補充的一點是,在Perl中胖箭頭"=>"與逗號","是完全等價的,因此上面右邊的散列中的胖箭頭完全可以用逗號代替。使用胖箭頭的唯一理由就是它清晰的表達了各個鍵與值映射關系。
4、引用(reference)和地址
應該說引用使得Perl中數組和哈稀變得更鍵靈活而強大。引用表達的是一種“指向”的關系,因此它類似於C語言中的指針。比如你創建一個引用讓它指向一個數組:
my $ref1 = \@arr; my $ref2->[0] = "first"; $ref2->[2] = 3;
這兩種方法都會創建一個引用,第一種方法要求數組@arr被已經申明。第二種方法到更像是創建了一個類似於數組的怪物,之所以說它是怪物是因為你如果需要訪問數組的某個元素,你只能使用箭頭符號"->"來完成下標的指定,類似於:
my $var = $ref->[num];
這里num顯然是一個整數值。一般來說,引用的創建多用來指向到一個數組或者一個哈稀。創建一個引用指向一個標量似乎沒有太大的必要。
有了引用,我們就可以使用標量、數組以及哈稀來任意地構造我們自己的數據結構,比如:
my $arr_double->[0] = \(1, 2, 3); $arr_double->[1] = \(4, 5, 6); $arr_double->[2] = \(7, 8, 9);
這樣的二維數組你應該不會感到陌生和意外。那么“二維”哈稀呢?
my $hash_double->{'line1'}->{'row1'} = "first"; $hash_double->{'line1'}->{'row2'} = "second";
需要說明的是根本沒有“二維”哈稀這樣詭異的說法,它只是筆者的玩笑而已,當然如果你一定要把它戲稱為“二維”哈稀的話,那么也就你自己心里想想就好,千萬別在某個重要的會議上說出來。
二、運算符及其優先級
Perl下的運算符來基本上借鑒於兩種語言:C與Pascal。全部的運算符及其結合性如下:
操作符 | 結合性 | 完成的操作 |
() | 左 | 改變運算的優先級;列表操作符 |
-> | 左 | 引用操作符 |
++ -- | 左 | ++自增,--自減 |
** | 右 | 乘冪 |
\ ! ~ + - | 右 | 都是單目操作符,\取地址,!邏輯非,~按位非,+正號,-負號 |
=~ !~ | 左 | =~匹配綁定操作符,!~不匹配綁定操作符(這東西太詭異了) |
* / % x | 左 | *乘,/除,%求余,x字符串重復操作符 |
<< >> | 左 | 移位操作符 |
-X -r rand shift |
左 | 具名的單目操作符,-X與-r都是文件測試操作符,rand得到一個隨機值 |
< <= > >= lt le gt ge | 左 | “不等”關系運算符,前四個比較數值,后四個比較字符串 |
== != <=> eq ne cmp | 左 | “相等”關系操作符,前三個比較數值,后三個比較字符串 |
& | 左 | 按位與 |
| ^ | 左 | |按位或,^按位異或 |
&& | 左 | 邏輯與 |
|| | 左 | 邏輯或 |
.. ... | 左 | ..范圍操作符, |
?: | 右 | Perl中最詭異的操作符:三目(條件)操作符 |
= += x= .= | 右 | 賦值以及增量賦值操作符 |
, => | 左 | 逗號操作符;列表操作符(右結合性) |
not | 右 | 邏輯非 |
and | 左 | 邏輯與 |
or xor | 左 | or邏輯或,xor邏輯異或 |
如你所見,Perl中操作符很多很多,而且有很多冗余的,比如邏輯操作符有兩套,and/not/or/xor系之所以存在,是因為它們的優先級很低,這 樣使用它們有時你可以省敲一些括號。全部記住這些操作符及其優先級和更加讓人頭疼的結合性顯然是不現實的,並且也有悖於Perl程序懶惰的作風,所以合理 的使用圓括號是值得推薦的,也很有必要。
各個操作符具體的操作方法請參考任意一本講解Perl的書,當然我要推薦大駱駝書。
三、關於context(上下文)
上下文是一種很重要的概念,盡管我們未必留意到它,但是我們卻無時無刻不在使用它。比如,某次考試后,你問別人“嘿,第21題怎么回事?”,你的同學應該可以立刻直到你在問什么。但如果你把這句話同樣的說給剛剛睡醒爺爺聽,他一定會感到莫名其妙。這就是上下文的概念。
在Perl中,上下文就是概念就是:同一個表達式,出現在不同的地方會有不同的結果和意義。
我們直到Perl中最最常見的就是標量和列表了,這形成了Perl中兩種最常見上下文環境:標量上下文和列表上下文。標量上下文中的表達式被期望返回一個標量值,而列表上下文中的表達式則被期望返回一個列表。比如:
4 * something shift something keys something
這里,something出現在三個地方:乘號操作符期望它是一個數值,因此第一個something處於標量上下文,更准確點是數值上下文;shift操作符期望它是一個列表,因此第二個something就處於列表上下文;最后keys函數期望something是一個散列(哈稀結構),所以最后一個something就處於散列上下文。
需要補充說明的是,散列也是一種列表,只是散列的元素個數為偶數個,且索引為偶數的元素要求在該散列中獨一無二、各不相同而已。所以最常見的上下文還是標量上下文和列表上下文。
1、在標量上下文中使用產生列表的表達式
這個情況沒有統一的規定,但是,大多數情況下會返回列表元素的個數,這基本上就是你期望的。盡管如此,我還是打算詳細說明一些比較“特殊”的。
某些表達式不會在標量上下文中返回任何值。比如,sort在標量上下文中返回的是undef。有人或許會認為應該返回列表元素的個數,可是誰會通過對列表排序來獲得列表的個數呢?
某些表達式在標量上下文中會返回列表所有元素連接而成的串。比如reverse,在標量上下文中,它會返回逆序后的字符串(先將列表中所有元素串連在一起,在對結果進行反序處理)。
另外需要強調的是,對於print操作符,其后是一個列表上下文。
2、在列表上下文中使用產生標量的表達式
這種情況十分簡單:它會自動產生一個僅含此標量值的列表,即使這個標量值為undef。需要注意的是空列表和僅含一個元素且其值為undef的列表是兩個不同的概念。如下:
my @arr = undef; my @arr = ();
前者的元素個數是1,二后者是名副其實的空列表,它的元素個數為0。
四、語句結構
1、判斷條件和“布爾”值
Perl中沒有專用的布爾類型的值,關系運算的結果也會是一個標量值,Perl中任何標量值都可以作為控制結構的判斷條件。Perl中判定一個標量為真還是假的規則很簡單:
(1)如果值為數值,0為假,所有其它數值為真;
(2)如果值為字符串,空字符串(""或'')為假,所有其它字符串為真;
(3)如果不是數值也不適字符串,那么就先轉化成數值或字符串再進行判斷,所以undef為假,所有的引用都為真;
需要注意的一點就是:字符串'0'或"0"跟數字0是同一個標量值,所以也為假,這是非空字符串為假的唯一的例外。
對於列表,現將它轉化成標量值在進行判斷(也就是說控制結構的判斷條件是一個標量上下文)。
2、條件控制結構
if控制結構如下:
if (condition1) { something; } elsif (condition2) { something; } else { something; }
注意,Perl中控制結構的花括號不是可有可無的,而是必須存在的。Perl中暫時沒有switch結構,在Perl6中或許會有這個結構。其它分支選擇結構還有unless結構,只是比較少用。
3、循環控制結構
while循環控制結構如下:
while (condition) { something; }
foreach循環控制結構如下:
foreach $var (@arr) { something; }
for循環結構如下:
for (initialization;condition;increment) { something; }
需要注意的是,Perl並不區分for和foreach這兩個關鍵詞,也就是說,對於Perl解釋器foreach與for表達同樣的含義,因此不管是for還是foreach都可以引領這兩種循環結構。其它循環結構還有until結構,但是用的比較少。
4、函數
函數以關鍵詞sub申明,一個函數結構如下:
sub function_name { something; }
調用函數的方法如下:
&function_name(parameter_list);
對於函數,需要注意的是在調用時,函數的參數是一個列表上下文,所以才叫做參數列表嘛。傳給函數的參數被放在函數的下划線變量@_中。Perl中函數的返回值可以通過return語句顯示返回,如果沒有return語句,則返回最后一個條語句的執行結果。