最近在看 Greg London 的Impatient Perl治筒,再次感受 Perl 的奇怪(不過之前用過 Ruby屉栓,有些東西也見怪不怪了)。
都說 Perl 是以實用為第一設(shè)計準(zhǔn)則的耸袜,這是否就是說它簡單友多,限制很少,同時并不漂亮(統(tǒng)一的形式堤框,更少的語法域滥,比如 Lisp ),因為在現(xiàn)實中千奇百怪的需求面前它選擇了妥協(xié)(折中更好聽些)蜈抓?
都說 Perl 代碼很丑(寫一遍就扔掉启绰,后面很難看懂(包括本人)),是否是因為Perl 本身松懶的語法養(yǎng)成了Perl 程序員的隨性沟使?
都說Perl 有很多奇怪的預(yù)設(shè)變量委可,提高了初學(xué)者的門檻,但在我看來這只是Perl 眾多奇特風(fēng)俗中的一個格带。
說明:
我憎恨早期翻譯計算機領(lǐng)域那幫人的隨意撤缴,耶穌會引入God, Lord,gratia 之類的詞時還專門挑選了一些漢語里最接近的詞(天主叽唱、上帝、圣恩)來表達呢微宝,你們就隨隨便便地把hash 譯作哈希棺亭,array 叫做數(shù)組,Object Oriented 稱為面向?qū)ο蟆泽恚旅嫖也捎米约旱姆g(你可能不習(xí)慣镶摘,但這正如Perl 有自己的思維習(xí)慣):
- array,序列(突出它是有序的岳守,而且對存儲的元素沒有限制)凄敢;
- list,序列(在我看來湿痢,list 就是不能修改的序列涝缝?扑庞??)拒逮;
- hash罐氨,字典(其實也想過用映射表的,但字典更通俗一些滩援。關(guān)聯(lián)序列的叫法沒說出它無序的性質(zhì))栅隐;
- lexical variable,局部變量(總覺得沒表達出它是被限制在lexical scope 中的意思)玩徊;
- Object Oriented租悄,物件導(dǎo)向(臺灣的譯法,的確恩袱,OO就是圍繞Object 和其間的關(guān)系來設(shè)計程序的)恰矩;
前導(dǎo)符
拿命名來說吧,大多數(shù)語言雖然都提倡給變量取個好名字憎蛤,但一般都沒什么限制外傅,Perl 就非得搞個前導(dǎo)符(sigil):
- 標(biāo)量(scalar)前面得貼上$(因為$ 長得像S -_-!!);
- 序列(array)前是@(想必你也猜到了@ 長得像a )俩檬;
- 字典(hash)更絕萎胰,弄了個% (看著像不像key / value);
- 子程序(subroutine)用& 作前導(dǎo)符(可選棚辽,一般都不寫技竟,誰讓你聲明的時候有sub 這么明顯的標(biāo)識呢。& 可能源于C 里面的取地址)屈藐。
看似Perl 還算嚴謹榔组,名字上區(qū)分都這么嚴格,那么請看下面這個例子:
use Data::Dumper;
my $var = 1;
my @var = (1, 2, 3, 4, 5, 6);
my %var;
$var{1} = 2;
$var{3} = 4;
$var{5} = 6;
print Dumper /$var, /@var, /%var;
$VAR1 = /1;
$VAR2 = [
1,
2,
3,
4,
5,
6
];
$VAR3 = {
'1' => 2,
'3' => 4,
'5' => 6
};
看到了吧联逻,同一個名字加不同的前導(dǎo)符會被 Perl 解釋成不同的數(shù)據(jù)結(jié)構(gòu)(當(dāng)然這種做法是不提倡的啦搓扯,但你也可以由此看到 Perl 內(nèi)部的某種統(tǒng)一)。
my
Perl 程序中聲明變量一般喜歡在前頭加上my包归,作用有點像把變量限定為局部的(正式名稱叫l(wèi)exical variable)锨推。一旦出了所在的詞法作用域(lexical scope),加了關(guān)鍵字my 的變量就不再有效公壤。那你干嘛不寫local换可,弄個什么my,你咋不弄個your呢厦幅。你還真別說沾鳄,your是沒有,our倒有一個确憨。被聲明為our 的變量只能被它所在的名字空間(namespace)直接引用(main 空間里的除外)译荞,別的名字空間要想引用必須寫全稱瓤的,即名字空間::變量名〈沤罚回到my 的話題上堤瘤,局部變量不屬于任何名字空間,出了所在的塊就不能再被訪問浆熔,除非它有個還沒被銷毀的引用本辐。
use Data::Dumper;
my $ref;
{
my $str = 'I am Pope.';
$ref = /$str;
}
Dumper print $str;
Dumper print $ref; # I am Pope.
序列和字典
我認為,一門語言越接近人類語言医增,它對歧義的包容和推理能力越強慎皱,即在不同的語境下,同一句話能傳達不同的意思叶骨。Perl 的序列在不同的語境(context) 下就有不同的含義茫多。
Perl 的序列定義時用@ 前導(dǎo)符,要訪問序列中的元素時卻使用$ 前導(dǎo)符加[索引]忽刽,讓人很是不解(難道是為了強調(diào)取得的是個標(biāo)量天揖?!)跪帝。Perl 的字典類似今膊,但不用方括號,而用花括號(像Ruby 那樣統(tǒng)統(tǒng)方括號不好嗎)
最末一個元素的索引可以用“$#序列名”取到伞剑,據(jù)說這一丑陋的語法來自C shell斑唬。我取最末元素的下標(biāo)干啥,想知道序列的容量還得加個1黎泣,多麻煩恕刘,而且你還提供了另一種更簡潔的方式來訪問最末元素——負數(shù)索引:$ary[$#ary] 等價于 $ary[-1]。
Perl 把要存儲的數(shù)據(jù)放在圓括號中抒倚,用逗號隔開(你也可以不用逗號褐着,改用“肥逗號”,即“=>”衡便。不要驚奇献起,Perl 的世界里一切皆有可能)。如果你懶得打逗號镣陕,也可以把東西放進qw()(quoted words 或者quoted by whitespace 的簡寫)里,用空格隔開就行姻政。不喜歡圓括號也沒關(guān)系呆抑,可以隨便換成任何成對的符號。現(xiàn)在看著很方便吧汁展,一會你就不會這么想了鹊碍,qw 的七姑八姨(q, qq, qx, qr)馬上就來厌殉,一定讓你滿眼金光。
Perl 口口聲聲說序列只能包含標(biāo)量侈咕,不能包含其他序列公罕,那這程序也沒見錯啊:
my @ary = (a, e, i, o, u);
my @lst = (@ary, "hey"); # (a, e, i, o, u, hey)
只是Perl 會把傳入的序列抹平耀销。要想真正實現(xiàn)嵌入楼眷,得加上方括號:
my @lst = ([@ary], "hey"); # ([a, e, i, o, u], hey)
更詭異的是,用$lst[0] 只能得到類似“ARRAY(0x10086cfc8)”的東西熊尉,要想取得值必須這么干:
@{$lst[0]}
Perl 用$_ 作缺省變量罐柳,這點無可厚非,Python, Mathematica 不都習(xí)慣用‘_’嗎狰住。
bless()
前面的要說奇怪张吉,頂多也就是另一種約定俗成,Perl 里的Object Oriented 才叫一絕催植。Perl 中沒有class或是類似的關(guān)鍵字肮蛹,它用模塊來模擬類(說是模擬,因為它缺少類的很多功能创南,比如數(shù)據(jù)的私有伦忠??扰藕?)
Perl 的每個包(package)對應(yīng)一個.pm (perl module)文件缓苛,且包的名字和.pm 文件的名字一致(一般自定義的包名各單詞首字母大寫,內(nèi)置的包名一般用全小寫)邓深。如果一個文件里放了多個包未桥,use 的時候會找不到對應(yīng)的文件。Perl 還要求所有的模塊以“1;” 結(jié)尾芥备,否則會出錯冬耿。
模塊就模塊嘛,非得叫什么包萌壳,還要求虛擬的模塊與實體的文件一一對應(yīng)亦镶。這還不說,還要用“1袱瓮;” 來表示模塊結(jié)束缤骨,表明返回了一個真值-_-!!
聲明了包,你就可以用包名::函數(shù)名(限定包名)的方式調(diào)用模塊中定義的函數(shù)了(有點像類函數(shù)尺借?绊起??)
下面該介紹Perl 里物件導(dǎo)向機制的主角—— bless() 燎斩。其實bless() 本身很簡單虱歪,僅僅是篡改ref() 的返回值蜂绎。
還記得ref()嗎?它能判斷出傳入值的類型:ARRAY, SCALAR, HASH, CODE, 或是空串(表示未知類型或傳入的不是一個引用)笋鄙,功能上有點像Ruby 里的class() 函數(shù)师枣。
use Data::Dumper;
@ary = (1, 2, 3);
%hash = {you=>2, me=>4};
$foo = sub {
print "hey";
};
print Dumper ref(/@ary), ref(/3), ref(/%hash), ref($foo), ref(Animal);
$VAR1 = 'ARRAY';
$VAR2 = 'SCALAR';
$VAR3 = 'HASH';
$VAR4 = 'CODE';
$VAR5 = '';
而bless() 篡改的恰恰是(也只影響)ref() 的返回值,即間接地修改了傳入值的類型(說你是你就是萧落,不是也是??)践美。
說到這,你可以隱隱約約看到bless() 和Perl 的物件導(dǎo)向編程間千絲萬縷的關(guān)系了铐尚〔β觯可能你會奇怪,好名字多的是宣增,為什么叫bless玫膀?Perl 老爹的思維是這樣的,被祈禱過的(blessed) 水雖然和普通水別無二致爹脾,卻會被稱為“圣水”帖旨,只是變了個名字,其它什么都沒變灵妨〗庠模看到了吧,bless() 改變的僅僅是引用的名字泌霍,并沒有改變引用的內(nèi)容货抄。但僅僅是這點差別,卻可能產(chǎn)生行為上的差異朱转。
前面不是說可以通過限定包名的方式調(diào)用函數(shù)蟹地,還可以等價地寫成“調(diào)用者 -> 函數(shù)名”的形式。
use Animal;
Animal::Speak; # Woof!
Animal->Speak; # Woof!
其實藤为,它倆還是有點不同的怪与,后者會把調(diào)用者的名字也傳進@_。
package Animal;
use Data::Dumper;
sub Speak {
print Dumper(/@_);
}
1;
use Animal;
Animal::Speak(3); # $VAR1 = [3];
Animal->Speak(3); # $VAR1 = ['Animal', 3];
Perl 用use base 語句實現(xiàn)繼承缅疟,而“use base 基類名”其實是將基類push 進@ISA (一個包含了當(dāng)前包所有基包的序列分别,ISA 就是is a)。
現(xiàn)在似乎一切都有了存淫,那為什么說bless() 是Perl 物件導(dǎo)向機制的基礎(chǔ)呢耘斩?有了bless() 你就可以指鹿為馬了:
use Animal;
my $inv = bless {}, "Animal";
$inv->Speak(2);
那又怎樣?如果你把它放到函數(shù)里面呢桅咆?
package Animal;
sub New {
my ($inv, $name) = @_;
my $obj = {};
$obj->{Name} = $name;
bless($obj, $inv);
return $obj;
}
sub Speak {
my ($obj) = @_;
my $name = $obj->{Name};
print "$name growls/n"
}
1;
use Animal;
my $lion = Animal->New('Samon');
$lion->Speak(); # Samon growls
New() 可以這樣簡寫:
sub New {
my ($inv, $name) = @_;
return bless({Name=>$name}, $inv);
}
在我看來煌往,Perl 有一套復(fù)雜而特別的習(xí)俗。它總的原則就是少敲字轧邪,所以不斷地在語言里加入各種記號刽脖,語言的風(fēng)格也鼓勵程序員運用這些短小、怪異的記號忌愚。這種風(fēng)俗的結(jié)果就好像沒有規(guī)劃(或者前期有規(guī)劃曲管,建造完成后無管理)的下水道系統(tǒng),需要時臨時挖一條硕糊,遇到舊管道就繞過(繞不過就可以抱怨了院水,“當(dāng)時怎么規(guī)劃的!”)简十,時間久了檬某,整個語言就變成了一個無法理解的龐然大物(從Perl 6 的開發(fā)可見一斑)。對我而言螟蝙,這些捷徑就像結(jié)繩記事一樣恢恼,久而久之,自己都搞不清為什么結(jié)繩了胰默,這時才肉牛滿面——還不如當(dāng)初多寫幾句呢-_-!
P.S. 譯文《What's wrong with Perl》
這是Lars Marius Garshol2002年1月寫的一篇文章场斑,鑒于近十年來Perl 沒有太大的變化,我決定翻譯這篇老文牵署。
寫在開始之前
本文所談僅僅是我個人對Perl 的理解漏隐。我歡迎大家提出自己的看法。我看到很多人在Usenet 上發(fā)問奴迅,怎么學(xué)習(xí)Perl青责,在這,我只想陳述自己的看法——我會告誡他們不要學(xué)習(xí)Perl取具。
如果你認為本文有什么明顯的錯誤脖隶,請與我郵件聯(lián)系。如果你只是不同意者填,也請告訴我浩村。我會盡可能糾正文中的錯誤。
可能還需要解釋為什么我把Perl 稱為駱駝(the Camel)占哟。Perl 之父Larry Walls 寫過一本Perl 全書《Programming Perl》心墅,O’Relly 出版社發(fā)行這本書的時候用一只駱駝作為封面。從此榨乎,這本書也被叫做“駱駝書”怎燥,而Larry Wall 也經(jīng)常用駱駝來指代Perl。
本文使用Python 1.5.2和Perl 5.005蜜暑,如果以后的版本有什么新功能铐姚,請告之。
初識“駱駝”
我是在97年初開始學(xué)習(xí)Perl 5的。我下了Patrick M. Ryans 寫的一篇很好的Perl 簡介隐绵,感覺很多用C, Pascal, Java 很難處理的問題在Perl 里迎刃而解之众。Perl 在文本處理和系統(tǒng)交互方面如有神助。我還讀了Randal Schwartz 的“Learning Perl”(也被稱為羊駝書(llama book))依许。
我快速翻閱了這本書棺禾,發(fā)現(xiàn)了一些有意思的新功能。我僅僅花了半個小時就完成了我的第一個程序峭跳,用來讀web 服務(wù)器的日志膘婶,然后統(tǒng)計各頁的訪問次數(shù)。它不僅運行得很好蛀醉,而且似乎能一些忽略一些不重要的錯誤悬襟,要是用C/Pascal/Java 來寫恐怕早就崩了。
(這個程序更新了好幾版拯刁,不少人在用脊岳。可見筛璧,Perl 不是不夠強大逸绎,而是不夠方便)
愛而生厭
我曾經(jīng)癡迷這門語言。隨著了解的深入夭谤,我漸漸發(fā)現(xiàn)一些不合口味的東西棺牧。我把這些東西列成表,現(xiàn)在朗儒,這表已經(jīng)很長了颊乘。
容易混淆的語法
我承認犧牲了一點可讀性……
——Larry Wall
我開始厭惡Perl 最初是因為它的語法。Perl 是門復(fù)雜的語言醉锄,有很多操作符和特殊的語法乏悄。這就意味著,代碼越長恳不,隱含的語法錯誤就越多檩小,而且復(fù)雜語法也給讀代碼造成了更多的困難。這樣烟勋,理解或者維護別人的代碼就變得更難了规求。
我追求簡潔漂亮的代碼,對那些容易造成混淆的特性敬而遠之卵惦,但即便如此阻肿,它還是很難讀懂。下面就是一個常見的例子:
foreach $Key (@SearchEngines) {
if ($fields[11] =~ /$Key/i) {
$HitFrom[4]++; #Yes, search engine
$SEReferrals{$SENames{$Key}}++;
$PageRefs{$fields[6]}{$SENames{$Key}}++;
$found=1;
last;
}
}
這還不算最糟的沮尿,這有個產(chǎn)生Soundex (譯注:一種語音算法丛塌,利用英文單詞的讀音計算近似值,值由四個字符構(gòu)成,第一個為字母赴邻,后三個為數(shù)字)值的Perl 函數(shù):
sub soundex
{
local (@s, $f, $fc, $_) = @_;
push @s, '' unless @s; # handle no args as a single empty string
foreach (@s)
{
tr/a-z/A-Z/;
tr/A-Z//cd;
if ($_ eq '')
{
$_ = $soundex_nocode;
}
else
{
($f) = /^(.)/;
tr/AEHIOUWYBFPVCGJKQSXZDTLMNR/00000000111122222222334556/;
($fc) = /^(.)/;
s/^$fc+//;
tr///cs;
tr/0//d;
$_ = $f . $_ . '000';
s/^(.{4}).*/$1/;
}
}
wantarray ? @s : shift @s;
}
這還不是最難讀的印衔。Perl Journal 雜志每年會舉辦一屆最糟Perl 代碼大賽。 獲勝者的代碼要么是單詞讀不懂乍楚,要么是意思猜不透(這不能說明Perl 可讀性不強当编,只是有太多鬼靈精怪的東西罷了)
程序的可讀性
有人讀這篇筆記的時候會說“不管什么語言,總有人能寫出狗屎一般的代碼徒溪!”。確實金顿,但也要看到有些語言似乎倡導(dǎo)晦澀難懂的風(fēng)格臊泌,有些則倡導(dǎo)簡單明快。
從我自身和其他一些人的代碼來看揍拆,Perl 屬于前者渠概。在Perl 代碼堆里,很多腳本都很短以至于不難讀懂嫂拴,但你隨便翻翻還是能每兩三頁就看到一個像前面的Soundex 算法那樣的例子播揪。
有些人爭辯說Perl 比其他大多數(shù)語言都更接近自然語言,至少對我來說這話不假筒狠。但自然語言不僅異常復(fù)雜猪狈、含混不清,而且有大量的詞義差別很小的近義詞辩恼。我可不想我的程序變成那個樣子雇庙,但它有這方面的趨勢了。你是那一類呢灶伊?
太多的特殊構(gòu)件疆前??聘萨?
Perl 把很多特性直接寫進內(nèi)核竹椒,而不是作為獨立的庫來調(diào)用。正則表達式就是個例子米辐。Perl 的正則表達式有自己的語法胸完,這樣在處理常用事務(wù)時很方便,但也意味著你不能借用物件導(dǎo)向儡循?舶吗?的優(yōu)勢。
Perl 有個叫format 的特殊構(gòu)件择膝?誓琼?,用這玩意你可以生成漂亮的文本報告。format 很好使腹侣,但是被做進語言里了郊艘,所以,你不能創(chuàng)建format 序列客扎,把它們作為函數(shù)的返回值……很多情況下它都不夠方便胧瓜。
你可以操作文件,但因為他們被內(nèi)建到語言中跺株,所以我從沒搞懂它們是怎么工作的复濒??乒省?巧颈。我曾經(jīng)嘗試使用引用,但從沒成功過袖扛。
難于構(gòu)建復(fù)雜數(shù)據(jù)結(jié)構(gòu)
Perl 文檔里用了好幾頁來演示如何序列和字典多重嵌套的數(shù)據(jù)結(jié)構(gòu)砸泛。我反反復(fù)復(fù)讀了好幾遍,費了老鼻子勁才搞清楚工作原理蛆封。我發(fā)現(xiàn)了一些很奇怪的東西唇礁,如果是用其他語言完全不用考慮這些問題。
在Lisp 里惨篱,這樣來賦給變量a 一個序列:
(setq a '(1 2 3 4))
其任意元素(以第一個為例)可以為另一序列:
(setq b '((0.8 0.9 1) 2 3 4))
如果用Perl盏筐,第一個序列可以這樣表示:
@a=(1,2,3,4);
這是第二個:
@b=((0.8,0.9,1),2,3,4);
(變量前的@ 符說明這些變量是序列)目前為止還行,接下來我們試試訪問元素妒蛇。
在Lisp 里面机断,訪問第一個元素要這樣寫:
(first a)
Lisp 返回1
同樣地,第二個序列b 的第一個元素:
(first b)
Lisp 返回
(0.8 0.9 1)
現(xiàn)在試試Perl:
$a[0]
返回1
變量名前的$ 是告訴Perl 我們想要一個單值(Perl 術(shù)語叫scalar)绣夺,而不是一個序列吏奸。[0] 標(biāo)明我們想要這個序列的第一個元素的值。就像其他大多數(shù)語言和API 接口一樣陶耍,Perl 從0開始計數(shù)奋蔚。
我們試試
$b[0]
Perl 很高興地給我們返回了0.8
沒錯,Perl 會把嵌套的序列抹平烈钞,也就是說序列b 現(xiàn)在有6個地位平等的(譯注:原文是consecutive泊碑,我覺得作者想說的是:前三個元素并不屬于嵌套在序列中的序列)元素。
要想獲得嵌套序列毯欣,我們要這么寫
@b=([(0.8,0.9,1)],2,3,4);
注意方括號的作用是:在外層序列第一個元素的位置上置一個引用馒过,這個引用指向內(nèi)層序列。
(匿名序列P锍8购觥@蠢邸!)
現(xiàn)在我們再試試:
$b[0]
返回ARRAY(0xb75eb0)
現(xiàn)在我們想要的是元素的內(nèi)容窘奏。問題出在$ 上嘹锁,Perl 認為我們想要一個單值,所以返給我們一個序列的引用着裹,而不是序列本身(序列不是單值)领猾。
這樣看來我們得用
@b[0]
@告訴Perl 我們想要的是序列的內(nèi)容。試一下骇扇,
ARRAY(0xb75eb0)
丫的摔竿,還是這個。這一刻匠题,我沒去想這是為什么拯坟,而是放棄了。
幾周以后韭山,我看到一個帖子,給了我一線希望:在訪問序列中引用的內(nèi)容時冷溃,要這樣寫:
@{$b[0]}
終于拿到了
(0.8 0.9 1)
現(xiàn)在钱磅,我可以用上嵌套序列或是嵌套字典了。(譯注:想起我的本科畢業(yè)設(shè)計似枕,需要一個很復(fù)雜的數(shù)據(jù)結(jié)構(gòu)盖淡,序列、字典一燉亂套凿歼,現(xiàn)在想來真是慶幸用的是Ruby _)
現(xiàn)在褪迟,回想一下:你真的需要嵌套序列嗎?
定義接口
Perl 的另一個顯著缺陷就是缺少函數(shù)簽名(函數(shù)答憔,Perl 里叫子程序(subroutine))味赃。大多數(shù)語言都提供了函數(shù)簽名,把參數(shù)的名字(有些甚至附上類型)羅列出來虐拓。但Perl 沒這么做心俗。
例如,這樣一段Java 代碼
public String substring(String str, int from, int to) {
用Perl 改寫就成了這樣
sub substring {
local($str, $from, $to) = @_;
換言之蓉驹,你手動解析參數(shù)序列城榛。Perl 最近加入了原型記號(the notion of prototypes),所以你可以這么寫
sub substring($, $, $) {
local($str, $from, $to) = @_;
這樣态兴,Perl 會檢查參數(shù)的個數(shù)對不對狠持。但這不是強制的,事實上很多Perl 代碼都沒這么寫瞻润。
事情還沒有結(jié)束喘垂,很多程序員都不會像上面那樣去解析參數(shù)甜刻,使得代碼更難讀了,而要自動生產(chǎn)文檔似乎也變得不可能王污。
進而別的高級語言中的那些特性罢吃,比如參數(shù)指定(keyword arguments),你也用不了了(當(dāng)然你也可以用字典自己實現(xiàn))昭齐。例如尿招,如果你在Common Lisp 中用一個叫make-hash-table 的函數(shù)來創(chuàng)建字典,這個函數(shù)帶以下參數(shù):
- test(用作判定是否與某個值相等的函數(shù))
- size(期望的元素個數(shù))
- rehash-size(字典擴容后的容量)
- rehash-threshold(超過該閾值即需要擴容)
下面這些創(chuàng)建字典的方式都沒錯:
(make-hash-table)
(make-hash-table :test #'eq)
(make-hash-table :size 1000)
(make-hash-table :rehash-size 2.0 :rehash-threshold 0.7)
如果你用到的函數(shù)參數(shù)很多阱驾,這種特性就很有用就谜,既方便又清晰。你也可以在Perl 里這么干里覆,但是不鼓勵丧荐,自動生成文檔也不方便,代碼既不容易讀懂喧枷,肯定也不如Common Lisp 中那么方便:
(defun make-hash-table(&key test size rehash-size rehash-threshold)
沒有真正的物件導(dǎo)向
雖然物件導(dǎo)向不如很多人相信的那么神奇虹统,雖然Perl 也支持,但只是半路出家隧甚,可以說是在這門語言生命的后期(车荔??戚扳?)才被添加進來忧便。
如此一來,普通文件帽借、套接字(socket)珠增、字典和序列都不是原生物件,就意味著它們支持的接口本應(yīng)該更方便的砍艾。Perl 的新版本把這些東西打包成物件導(dǎo)向風(fēng)格的模塊蒂教,這樣只要遵從Perl 提供的協(xié)議,你就能自己去實現(xiàn)這些協(xié)議辐董。但這樣一來悴品,你就不大能分清是普通的file handle,還是file object了简烘。
還有就是苔严,當(dāng)你創(chuàng)建一個物件時,需要自己去管理物件內(nèi)部的構(gòu)件孤澎。在Perl 中届氢,需要手動創(chuàng)建物件。類(class)被聲明為包(package)覆旭,包中的函數(shù)就成了類的方法退子。你需要一個映射表作為物件的原材料岖妄,然后篡改它的引用的類型(用內(nèi)置函數(shù)bless())。手冊里perlobj 那部分具體解釋了Perl 的物件特性寂祥,推薦用下面的模版來初始物件:
package MyClass;
sub new {
my $class = shift;
my $self = {};
bless $self, $class
$self->initialize(); # do initialization here
return $self;
}
對于初識物件荐虐,還有其他方法,但可能會出現(xiàn)繼承方面的問題丸凭。個人覺得福扬,用這種方式實現(xiàn)物件導(dǎo)向真是不可思議。同樣的東西惜犀,用Python 來寫就很簡單:
class MyClass:
pass
如此笨拙的定義方式讓你很難察覺某塊代碼實際上是在定義類铛碑,也很容易導(dǎo)致物件創(chuàng)建錯誤。
小結(jié)
總的說來虽界,Perl 是門寬泛而復(fù)雜的語言汽烦,需要花很長時間來學(xué)習(xí)。在我看來這種復(fù)雜性是不必須的莉御,一門簡單的語言或許能取到更好的效果撇吞。我想這也意味著許多一般水平的Perl 開發(fā)者寫著次優(yōu)的代碼。
只有很少的Perl 開發(fā)者能寫成普適的可重用模塊礁叔,因為你必須非常了解這么語言梢夯,很多東西需要花費大量的時間來研習(xí),但這門語言本身卻不鼓勵花費如此之多的時間來學(xué)習(xí)如何寫出這樣的代碼(譯注:Perl 是門務(wù)實的語言晴圾,需要啥補啥)。
發(fā)現(xiàn)Python
(譯注:后面是說作者如何轉(zhuǎn)向Python 的噪奄,有點偏離本文的主題死姚,就不譯了_)
……