理解多種編程范型_第1頁(yè)
理解多種編程范型_第2頁(yè)
理解多種編程范型_第3頁(yè)
理解多種編程范型_第4頁(yè)
理解多種編程范型_第5頁(yè)
已閱讀5頁(yè),還剩169頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

理解多種編程范型

(七周七語(yǔ)言)目錄\h第1章簡(jiǎn)介\h1.1不走尋常路\h1.2語(yǔ)言\h1.3誰(shuí)應(yīng)該買(mǎi)這本書(shū)\h1.3.1學(xué)會(huì)如何學(xué)習(xí)\h1.3.2亂世英雄\h1.4誰(shuí)不應(yīng)該買(mǎi)這本書(shū)\h1.4.1超越語(yǔ)法\h1.4.2不是安裝指南\h1.4.3不是編程參考\h1.4.4嚴(yán)格督促\h1.5最后一擊\h第2章Ruby\h2.1Ruby簡(jiǎn)史\h2.2第一天:找個(gè)保姆\h2.2.1快速起步\h2.2.2從命令行執(zhí)行Ruby\h2.2.3Ruby的編程模型\h2.2.4判斷\h2.2.5鴨子類(lèi)型\h2.2.6第一天我們學(xué)到了什么\h2.2.7第一天自習(xí)\h2.3第二天:從天而降\h2.3.1定義函數(shù)\h2.3.2數(shù)組\h2.3.3散列表\h2.3.4代碼塊和yield\h2.3.5定義類(lèi)\h2.3.6編寫(xiě)Mixin\h2.3.7模塊、可枚舉和集合\h2.3.8第二天我們學(xué)到了什么\h2.3.9第二天自習(xí)\h2.4第三天:重大改變\h2.4.1開(kāi)放類(lèi)\h2.4.2使用method_missing\h2.4.3模塊\h2.4.4第三天我們學(xué)到了什么\h2.4.5第三天自習(xí)\h2.5趁熱打鐵\h2.5.1核心優(yōu)勢(shì)\h2.5.2不足之處\h2.5.3最后思考\h第3章Io\h3.1Io簡(jiǎn)介\h3.2第一天:逃學(xué)吧,輕松一下\h3.2.1開(kāi)場(chǎng)白\h3.2.2對(duì)象、原型和繼承\(zhòng)h3.2.3方法\h3.2.4列表和映射\h3.2.5true、false、nil以及單例\h3.2.6SteveDekorte訪談錄\h3.2.7第一天我們學(xué)到了什么\h3.2.8第一天自習(xí)\h3.3第二天:香腸大王\h3.3.1條件和循環(huán)\h3.3.2運(yùn)算符\h3.3.3消息\h3.3.4反射\h3.3.5第二天我們學(xué)到了什么\h3.3.6第二天自習(xí)\h3.4第三天:花車(chē)游行和各種奇妙經(jīng)歷\h3.4.1領(lǐng)域特定語(yǔ)言\h3.4.2Io的method_missing\h3.4.3并發(fā)\h3.4.4第三天我們學(xué)到了什么\h3.4.5第三天自習(xí)\h3.5趁熱打鐵\h3.5.1核心優(yōu)勢(shì)\h3.5.2不足之處\h3.5.3最后思考\h第4章Prolog\h4.1關(guān)于Prolog\h4.2第一天:一名優(yōu)秀的司機(jī)\h4.2.1基本概況\h4.2.2基本推論和變量\h4.2.3填空\(chéng)h4.2.4合一,第一部分\h4.2.5實(shí)際應(yīng)用中的Prolog\h4.2.6第一天我們學(xué)到了什么\h4.2.7第一天自習(xí)\h4.3第二天:離瓦普納法官開(kāi)演還有15分鐘\h4.3.1遞歸\h4.3.2列表和元組\h4.3.3列表與數(shù)學(xué)運(yùn)算\h4.3.4在兩個(gè)方向上使用規(guī)則\h4.3.5第二天我們學(xué)到了什么\h4.3.6第二天自習(xí)\h4.4第三天:維加斯的爆發(fā)\h4.4.1解決數(shù)獨(dú)問(wèn)題\h4.4.2八皇后問(wèn)題\h4.4.3第三天我們學(xué)到了什么\h4.4.4第三天自習(xí)\h4.5趁熱打鐵\h4.5.1核心優(yōu)勢(shì)\h4.5.2不足之處\h4.5.3最后思考\h第5章Scala\h5.1關(guān)于Scala\h5.1.1與Java的密切關(guān)系\h5.1.2沒(méi)有盲目崇拜\h5.1.3MartinOdersky訪談錄\h5.1.4函數(shù)式編程與并發(fā)\h5.2第一天:山丘上的城堡\h5.2.1Scala類(lèi)型\h5.2.2表達(dá)式與條件\h5.2.3循環(huán)\h5.2.4范圍與元組\h5.2.5Scala中的類(lèi)\h5.2.6擴(kuò)展類(lèi)\h5.2.7第一天我們學(xué)到了什么\h5.2.8第一天自習(xí)\h5.3第二天:修剪灌木叢和其他新把戲\h5.3.1對(duì)比var和val\h5.3.2集合\h5.3.3集合與函數(shù)\h5.3.4第二天我們都學(xué)到了什么\h5.3.5第二天自習(xí)\h5.4第三天:剪斷絨毛\h5.4.1XML\h5.4.2模式匹配\h5.4.3并發(fā)\h5.4.4實(shí)際中的并發(fā)\h5.4.5第三天我們學(xué)到了什么\h5.4.6第三天自習(xí)\h5.5趁熱打鐵\h5.5.1核心優(yōu)勢(shì)\h5.5.2不足之處\h5.5.3最后思考\h第6章Erlang\h6.1Erlang簡(jiǎn)介\h6.1.1為并發(fā)量身打造\h6.1.2JoeArmstrong博士訪談錄\h6.2第一天:以常人面目出現(xiàn)\h6.2.1新手上路\h6.2.2注釋、變量和表達(dá)式\h6.2.3原子、列表和元組\h6.2.4模式匹配\h6.2.5函數(shù)\h6.2.6第一天我們學(xué)到了什么\h6.2.7第一天自習(xí)\h6.3第二天:改變結(jié)構(gòu)\h6.3.1控制結(jié)構(gòu)\h6.3.2匿名函數(shù)\h6.3.3列表和高階函數(shù)\h6.3.4列表的一些高級(jí)概念\h6.3.5第二天我們學(xué)到了什么\h6.3.6第二天自習(xí)\h6.4第三天:紅藥丸\h6.4.1基本并發(fā)原語(yǔ)\h6.4.2同步消息\h6.4.3鏈接進(jìn)程以獲得可靠性\h6.4.4第三天我們學(xué)到了什么\h6.4.5第三天自習(xí)\h6.5趁熱打鐵\h6.5.1核心優(yōu)勢(shì)\h6.5.2不足之處\h6.5.3最后思考\h第7章Clojure\h7.1Clojure入門(mén)\h7.1.1一切皆Lisp\h7.1.2JVM\h7.1.3為并發(fā)更新\h7.2第一天:訓(xùn)練Luke\h7.2.1調(diào)用基本函數(shù)\h7.2.2字符串和字符\h7.2.3布爾值和表達(dá)式\h7.2.4列表、映射表、集合以及向量\h7.2.5定義函數(shù)\h7.2.6綁定\h7.2.7匿名函數(shù)\h7.2.8RichHickey訪談錄\h7.2.9第一天我們學(xué)到了什么\h7.2.10第一天自習(xí)\h7.3第二天:Yoda與原力\h7.3.1用loop和recur遞歸\h7.3.2序列\(zhòng)h7.3.3延遲計(jì)算\h7.3.4defrecord和protocol\h7.3.5宏\h7.3.6第二天我們學(xué)到了什么\h7.3.7第二天自習(xí)\h7.4第三天:一瞥魔鬼\h7.4.1引用和事務(wù)內(nèi)存\h7.4.2使用原子\h7.4.3使用代理\h7.4.4future\h7.4.5還差什么\h7.4.6第三天我們學(xué)到了什么\h7.4.7第三天自習(xí)\h7.5趁熱打鐵\h7.5.1Lisp悖論\h7.5.2核心優(yōu)勢(shì)\h7.5.3不足之處\h7.5.4最后思考\h第8章Haskell\h8.1Haskell簡(jiǎn)介\h8.2第一天:邏輯\h8.2.1表達(dá)式和基本類(lèi)型\h8.2.2函數(shù)\h8.2.3元組和列表\h8.2.4生成列表\h8.2.5PhilipWadler訪談錄\h8.2.6第一天我們學(xué)到了什么\h8.2.7第一天自習(xí)\h8.3第二天:Spock的超凡力量\h8.3.1高階函數(shù)\h8.3.2偏應(yīng)用函數(shù)和柯里化\h8.3.3惰性求值\h8.3.4SimonPeyton-Jones訪談錄\h8.3.5第二天我們學(xué)到了什么\h8.3.6第二天自習(xí)\h8.4第三天:心靈融合\h8.4.1類(lèi)與類(lèi)型\h8.4.2monad\h8.4.3第三天我們學(xué)到了什么\h8.4.4第三天自習(xí)\h8.5趁熱打鐵\h8.5.1核心優(yōu)勢(shì)\h8.5.2不足之處\h8.5.3最后思考\h第9章落幕時(shí)分\h9.1編程模型\h9.1.1面向?qū)ο螅≧uby、Scala)\h9.1.2原型編程(Io)\h9.1.3約束—邏輯編程(Prolog)\h9.1.4函數(shù)式編程(Scala、Erlang、Clojure、Haskell)\h9.1.5范型演進(jìn)之路\h9.2并發(fā)\h9.2.1控制可變狀態(tài)\h9.2.2Io、Erlang和Scala中的actor\h9.2.3future\h9.2.4事務(wù)型內(nèi)存\h9.3編程結(jié)構(gòu)\h9.3.1列表解析\h9.3.2monad\h9.3.3匹配\h9.3.4合一\h9.4發(fā)現(xiàn)自己的旋律第1章簡(jiǎn)介人們出于各種目的學(xué)習(xí)自然語(yǔ)言。學(xué)母語(yǔ)是為了生存,為了日常生活中與人正常交往。學(xué)外語(yǔ)的目的可就五花八門(mén)了。有時(shí)候,為了未來(lái)的職業(yè)發(fā)展或?yàn)榱诉m應(yīng)日益變化的生活環(huán)境,你不得不學(xué)習(xí)外語(yǔ);但有時(shí)候,你決心征服一門(mén)外語(yǔ),不是因?yàn)椴坏貌贿@么做,而是因?yàn)榘l(fā)自?xún)?nèi)心地想學(xué)。外語(yǔ)能帶你領(lǐng)略一片未曾見(jiàn)過(guò)的風(fēng)景。你甚至可能領(lǐng)悟一個(gè)道理:每學(xué)一門(mén)新的語(yǔ)言,思維方式都會(huì)發(fā)生改變。編程語(yǔ)言亦是如此。在這本書(shū)中,我將為你介紹七門(mén)各不相同的語(yǔ)言。不過(guò),我不會(huì)像你的媽媽那樣將吃的直接喂到你嘴邊。我更愿意做你的導(dǎo)游,帶你體驗(yàn)一次啟迪心智之旅,并由此改變你看待編程的視角。寫(xiě)這書(shū)的目的不是讓你成為專(zhuān)家,而是教會(huì)你比“Hello,World”更實(shí)用的知識(shí)。1.1不走尋常路假如我想新學(xué)一門(mén)編程語(yǔ)言或一種編程框架,一般會(huì)找一篇速成互動(dòng)教程看看。因?yàn)檫@類(lèi)教程中,先做什么、后做什么都已精心設(shè)計(jì)好。通過(guò)它們,我們可以更容易體會(huì)語(yǔ)言的妙處所在。當(dāng)然,扔掉教程,直接動(dòng)手實(shí)踐也未嘗不可,但說(shuō)白了,我就是想盡快發(fā)現(xiàn)語(yǔ)言的動(dòng)人心弦之處,盡快對(duì)它的語(yǔ)法糖和核心概念有個(gè)大體印象。然而多數(shù)情況下,我找不到稱(chēng)心如意的教程。受到篇幅限制,那些教程往往只介紹各門(mén)語(yǔ)言間相去無(wú)幾的皮毛。而這些皮毛,我又早已熟知。若想領(lǐng)會(huì)一門(mén)語(yǔ)言的精髓,它可就無(wú)能為力了。我想要的是那種痛快淋漓、深入探索語(yǔ)言本質(zhì)的感覺(jué)。本書(shū)將會(huì)給你這種感覺(jué)。不是一次,而是七次。你將從書(shū)中找到以下問(wèn)題的答案。?語(yǔ)言的類(lèi)型模型是什么?強(qiáng)類(lèi)型(Java)或弱類(lèi)型(C語(yǔ)言),靜態(tài)類(lèi)型(Java)或動(dòng)態(tài)類(lèi)型(Ruby)。本書(shū)側(cè)重于介紹強(qiáng)類(lèi)型語(yǔ)言,但各種靜態(tài)類(lèi)型和動(dòng)態(tài)類(lèi)型語(yǔ)言也都有所涉及。你將看到,語(yǔ)言在類(lèi)型模型間的權(quán)衡會(huì)對(duì)開(kāi)發(fā)者產(chǎn)生何種影響。語(yǔ)言的類(lèi)型模型會(huì)改變你對(duì)問(wèn)題的處理方式,還會(huì)控制語(yǔ)言的運(yùn)行方式。就類(lèi)型模型而言,書(shū)中的每門(mén)語(yǔ)言都堪稱(chēng)獨(dú)樹(shù)一幟。?語(yǔ)言的編程范型是什么?是面向?qū)ο螅╫bject-oriented,OO)、函數(shù)式、過(guò)程式,還是它們的綜合體?本書(shū)介紹的語(yǔ)言涵蓋了4種編程范型,有些語(yǔ)言還由幾種范型組合而成。你將看到一門(mén)基于邏輯的編程語(yǔ)言(Prolog)、兩門(mén)完全支持面向?qū)ο笏枷氲恼Z(yǔ)言(Ruby和Scala)、四門(mén)帶有函數(shù)式特性的語(yǔ)言(Scala、Erlang、Clojure和Haskell)及一門(mén)原型語(yǔ)言(Io)。這里有Scala這樣的多范型(multiparadigm)語(yǔ)言,也有Clojure這種多方法(multimethod)語(yǔ)言,后者甚至允許你實(shí)現(xiàn)自定義范型。本書(shū)最重要的任務(wù)之一,就是學(xué)習(xí)新的編程范型。?怎樣和語(yǔ)言交互?語(yǔ)言可編譯也可解釋?zhuān)梢杂刑摂M機(jī)也可以沒(méi)有。在本書(shū)中,如果某門(mén)語(yǔ)言帶交互命令行,將先通過(guò)交互命令行探索這門(mén)語(yǔ)言,當(dāng)我們處理規(guī)模較大的項(xiàng)目時(shí),還會(huì)轉(zhuǎn)而采用文件編程。我們接觸的項(xiàng)目不會(huì)特別大,因此無(wú)需深入研究打包(packaging)模型。?語(yǔ)言的判斷結(jié)構(gòu)(decisionconstruct)和核心數(shù)據(jù)結(jié)構(gòu)是什么?或許你會(huì)驚訝,在作判斷時(shí),居然如此多的語(yǔ)言都用到了與if和while的各種變型都不相同的結(jié)構(gòu)。你會(huì)見(jiàn)識(shí)到Erlang的模式匹配,還有Prolog的合一(unification)。至于數(shù)據(jù)結(jié)構(gòu),集合(collection)在任何語(yǔ)言中都扮演著至關(guān)重要的角色。對(duì)Smalltalk和Lisp這類(lèi)語(yǔ)言,集合刻畫(huà)了語(yǔ)言特征,而在C++和Java等語(yǔ)言中,集合更可謂無(wú)所不在,它們決定著用戶(hù)體驗(yàn),若沒(méi)了它們,語(yǔ)言勢(shì)必成為一盤(pán)散沙。因此,無(wú)論用哪一類(lèi)語(yǔ)言,都必須全面、透徹地理解集合。?哪些核心特性讓這門(mén)語(yǔ)言與眾不同?有些語(yǔ)言支持并發(fā)編程的高級(jí)特性,有些語(yǔ)言提供獨(dú)一無(wú)二的高級(jí)結(jié)構(gòu),比如Clojure的宏(marco)和Io的消息解釋?zhuān)╩essageinterpretation);有些語(yǔ)言包含性能強(qiáng)勁的虛擬機(jī),如Erlang的BEAM,它能讓Erlang構(gòu)建的容錯(cuò)分布式系統(tǒng)遠(yuǎn)遠(yuǎn)快于其他語(yǔ)言;有些語(yǔ)言提供專(zhuān)門(mén)針對(duì)特定問(wèn)題的編程模型,比如利用邏輯規(guī)則解決約束問(wèn)題。就算這些問(wèn)題全被你弄個(gè)一清二楚,你仍然成不了語(yǔ)言專(zhuān)家,哪怕只是其中一門(mén)語(yǔ)言。但你會(huì)明白,這幾門(mén)語(yǔ)言各自擁有哪些獨(dú)門(mén)絕技。下面,我們先看看本書(shū)介紹了哪幾門(mén)語(yǔ)言。1.2語(yǔ)言從眾多語(yǔ)言中,挑出本書(shū)包含的幾門(mén)語(yǔ)言,這一過(guò)程也許不像你想得那么復(fù)雜。我們只不過(guò)發(fā)了些調(diào)查問(wèn)卷,向本書(shū)的潛在讀者請(qǐng)教了一番。調(diào)查數(shù)據(jù)匯總上來(lái)時(shí),有八門(mén)語(yǔ)言入選希望最大。不過(guò),我先把JavaScript“踢”了出去,因?yàn)樗鼘?shí)在是過(guò)于熱門(mén)了,取而代之的是原型語(yǔ)言中熱門(mén)程度僅次于JavaScript的Io。隨后,我又把Python“踢”了出去,因?yàn)槲抑幌虢o面向?qū)ο笳Z(yǔ)言一個(gè)名額,而Ruby的票數(shù)多于Python。同時(shí),這也給一個(gè)出人意料的候選者讓出了位置——名單上位列前十的Prolog。下面,我給出成功入圍本書(shū)的最終名單以及挑選它們的理由。?Ruby。這門(mén)面向?qū)ο笳Z(yǔ)言高票當(dāng)選,因?yàn)樗粌H好用,而且好讀。我曾經(jīng)考慮過(guò)不介紹任何一門(mén)面向?qū)ο笳Z(yǔ)言,但我又想在其他編程范型與面向?qū)ο缶幊讨g作一些比較,因此,至少介紹一門(mén)面向?qū)ο笳Z(yǔ)言還是有必要的。相比于大多數(shù)程序員的日常用法,我想把它挖掘得更深入一些,以揭示設(shè)計(jì)者的良苦用心。我最終決定重點(diǎn)介紹Ruby元編程(metaprogramming),因?yàn)樗梢杂脕?lái)擴(kuò)展Ruby的語(yǔ)法。對(duì)于Ruby榜上有名的結(jié)果,我還是相當(dāng)認(rèn)可的。?Io。和Prolog一樣,Io也是本書(shū)頗具爭(zhēng)議的語(yǔ)言。它雖與商業(yè)成功無(wú)緣,但其兼具簡(jiǎn)單性和語(yǔ)法一致性的并發(fā)結(jié)構(gòu),卻是十分重要的思想。它的最簡(jiǎn)語(yǔ)法(minimalsyntax)功能強(qiáng)大,與Lisp的相似性也頗能給人留下幾分印象。Io不僅和JavaScript一樣同為原型語(yǔ)言,還有著獨(dú)一無(wú)二、韻味無(wú)窮的消息分發(fā)機(jī)制,因此在眾多編程語(yǔ)言之中,它也占有小小的一席之地。?Prolog。沒(méi)錯(cuò),Prolog年事已高,但它仍然威力無(wú)窮。它能輕松解出數(shù)獨(dú)問(wèn)題,這著實(shí)讓我大開(kāi)眼界。用Java或C語(yǔ)言時(shí),有些難題我殫精竭慮方能解決,用Prolog卻能干凈利落地搞定。承蒙Erlang發(fā)明者JoeArmstrong出手相助,我得以深刻體會(huì)到Prolog之妙,而且也正是深受Prolog影響,Erlang才得以問(wèn)世。如果你此前從未用過(guò)Prolog,我保證,它定會(huì)帶給你驚喜。?Scala。作為運(yùn)行于Java虛擬機(jī)上的新一代語(yǔ)言,Scala為Java系統(tǒng)引入了強(qiáng)大的函數(shù)式思想,同時(shí)也并未丟棄面向?qū)ο缶幊獭;仡櫄v史,我發(fā)現(xiàn)C++和Scala有著驚人的相似之處,因?yàn)閺倪^(guò)程式編程過(guò)渡到面向?qū)ο缶幊唐陂g,C++同樣起到了舉足輕重的作用。當(dāng)你真正融入Scala社區(qū)之后,你就會(huì)明白,為什么對(duì)于函數(shù)式語(yǔ)言程序員來(lái)說(shuō),Scala是異端邪說(shuō),而對(duì)于Java開(kāi)發(fā)者來(lái)說(shuō),Scala是天降福音。?Erlang。作為名單上歷史最悠久的語(yǔ)言之一,Erlang不僅是一門(mén)函數(shù)式語(yǔ)言,而且在并發(fā)、分布式編程、容錯(cuò)等諸多方面都有優(yōu)異表現(xiàn),真是想不火都難。CouchDB(新興的基于云的數(shù)據(jù)庫(kù))的創(chuàng)始人就選擇了Erlang,并且義無(wú)反顧地一直用它,只要花上點(diǎn)時(shí)間了解這門(mén)分布式語(yǔ)言,你就會(huì)明白原因所在。在Erlang幫助下,設(shè)計(jì)帶有并發(fā)、分布式、容錯(cuò)等特征的應(yīng)用程序?qū)⒆兊脽o(wú)比簡(jiǎn)單。?Clojure。這又是一門(mén)Java虛擬機(jī)語(yǔ)言,但正是這門(mén)Lisp方言,徹底顛覆了我們?cè)贘ava虛擬機(jī)上并發(fā)編程的思考方式。它是本書(shū)唯一在版本數(shù)據(jù)庫(kù)中使用同一種策略管理并發(fā)的語(yǔ)言。作為L(zhǎng)isp方言,Clojure或許擁有本書(shū)所有語(yǔ)言中最靈活的編程模型,因此絕不缺乏號(hào)召力。與其他Lisp方言不同的是,它不會(huì)帶那么多括號(hào),還有眾多Java庫(kù)和在各平臺(tái)上的廣泛部署作為堅(jiān)強(qiáng)后盾。?Haskell。它是本書(shū)唯一的純函數(shù)式語(yǔ)言,這也意味著,它根本不存在可變狀態(tài):只要使用相同的輸入?yún)?shù),去調(diào)用相同的函數(shù),就會(huì)返回相同的輸出。在所有強(qiáng)類(lèi)型語(yǔ)言中,Haskell擁有最令人稱(chēng)羨的類(lèi)型模型。和Prolog一樣,它也需要你花一些時(shí)間理解,但你得到的回報(bào)絕對(duì)物超所值。如果名單上沒(méi)有你鐘愛(ài)的語(yǔ)言,我深感抱歉。老實(shí)說(shuō),還真有語(yǔ)言狂熱分子給我發(fā)過(guò)好幾封恐嚇信。在本節(jié)開(kāi)始提到的民意調(diào)查中,我們總共列出了幾十門(mén)語(yǔ)言。我挑的這幾門(mén)語(yǔ)言未必是其中最出色的,但它們特點(diǎn)突出、個(gè)性鮮明,都具有重要的學(xué)習(xí)價(jià)值。1.3誰(shuí)應(yīng)該買(mǎi)這本書(shū)如果你是一名稱(chēng)職的程序員,想提高自己的編程水平,那你應(yīng)該買(mǎi)這本書(shū)。這話(huà)說(shuō)來(lái)有幾分含糊,請(qǐng)容我解釋一二。1.3.1學(xué)會(huì)如何學(xué)習(xí)DaveThomas是PragmaticBookshelf出版社的創(chuàng)始人之一,我這本書(shū)就是他們出版的。他每年都鼓勵(lì)數(shù)以千計(jì)的學(xué)生去學(xué)一門(mén)新語(yǔ)言。學(xué)過(guò)各式各樣的語(yǔ)言后,你最少也能挑出一門(mén)得心應(yīng)手的語(yǔ)言用用,并把其他語(yǔ)言的精華思想融入到這門(mén)語(yǔ)言的代碼中去。這本書(shū)的寫(xiě)作過(guò)程已經(jīng)深刻影響了我所編寫(xiě)的Ruby代碼。相比于過(guò)去,我編寫(xiě)的Ruby代碼中,函數(shù)式味道更加濃郁,且因重復(fù)部分變少而增加了可讀性。我在代碼中盡量縮減了可變變量的數(shù)量,還利用代碼塊和高階函數(shù)寫(xiě)出了更有效的代碼。此外,我也用到一些不大符合Ruby慣例,但會(huì)讓代碼更簡(jiǎn)明的技巧。學(xué)語(yǔ)言最理想的情況,是由它引領(lǐng)你踏上一條嶄新的職業(yè)道路。每十年左右,編程范型都會(huì)發(fā)生一次變革。幾年前,我感覺(jué)Java越來(lái)越別扭,于是就去體驗(yàn)了一把Ruby,看看怎么用它進(jìn)行Web開(kāi)發(fā)。經(jīng)過(guò)幾個(gè)過(guò)渡項(xiàng)目的磨合,我開(kāi)始重點(diǎn)發(fā)展Ruby方向上的業(yè)務(wù),從此徹底告別Java。我的Ruby生涯始于玩票,但隨之而來(lái)的,卻是事業(yè)的不斷發(fā)展壯大。1.3.2亂世英雄說(shuō)到本書(shū)讀者,他們大概還沒(méi)那么老,不至于經(jīng)歷過(guò)上一次編程范型的更新?lián)Q代?;叵雱倱Q到面向?qū)ο缶幊棠菚?huì)兒,我們遇到過(guò)好幾次挫折,不過(guò)話(huà)說(shuō)回來(lái),當(dāng)時(shí)的結(jié)構(gòu)化編程范型已完全無(wú)法應(yīng)付現(xiàn)代Web應(yīng)用的復(fù)雜性。Java編程語(yǔ)言的成功為Web應(yīng)用開(kāi)發(fā)打了一針強(qiáng)心劑,也因此奠定了面向?qū)ο缶幊踢@種新編程范型的地位。不過(guò),當(dāng)時(shí)很多開(kāi)發(fā)者已深深陷入了過(guò)時(shí)技術(shù)的桎梏中。他們?nèi)粝腠樌^(guò)渡到新編程范型,必須由內(nèi)到外重新打造思考編程的方式、手頭用于開(kāi)發(fā)的工具、設(shè)計(jì)應(yīng)用程序的方法等才行?,F(xiàn)在,我們可能正身處又一次變革的進(jìn)程當(dāng)中。這一次變革,新的計(jì)算機(jī)設(shè)計(jì)架構(gòu)將成為主要推動(dòng)力。在本書(shū)的七門(mén)語(yǔ)言中,五門(mén)都擁有強(qiáng)大的并發(fā)模型(Ruby和Prolog不在其列)。無(wú)論你用的編程語(yǔ)言會(huì)不會(huì)一夜之間物是人非,我敢向你保證,在應(yīng)對(duì)這場(chǎng)變革之時(shí),本書(shū)介紹的所有語(yǔ)言都能拿出令人信服的策略??纯碔o對(duì)future的實(shí)現(xiàn)、Scala的actor、Erlang的“任其崩潰”(letitcrash)哲學(xué),再看看Haskell如何把可變狀態(tài)拋到九霄云外、Clojure如何利用版本控制解決最為棘手的并發(fā)問(wèn)題,你就會(huì)相信這一點(diǎn)。當(dāng)然,那些看似平凡的語(yǔ)言也不可小覷,它們帶來(lái)的啟示同樣讓人嘖嘖稱(chēng)奇。Erlang這門(mén)用于多個(gè)云數(shù)據(jù)庫(kù)后臺(tái)的語(yǔ)言就是個(gè)極佳的例子。正是以Prolog為基礎(chǔ),JoeArmstrong博士創(chuàng)立了這門(mén)語(yǔ)言。1.4誰(shuí)不應(yīng)該買(mǎi)這本書(shū)如果你沒(méi)有讀過(guò)本節(jié),或讀過(guò)但不認(rèn)同其中觀點(diǎn),那你不應(yīng)該買(mǎi)這本書(shū)。買(mǎi)這本書(shū)等于跟我做了筆買(mǎi)賣(mài):你認(rèn)可我把重點(diǎn)放在編程語(yǔ)言本身而非詳盡的安裝過(guò)程上,我承諾在有限時(shí)間內(nèi)盡可能多地授業(yè)解惑。你要學(xué)會(huì)利用Google搜索那些細(xì)枝末節(jié),可別指望我會(huì)幫你解決各種安裝問(wèn)題。如此一來(lái),我才有空間深入挖掘語(yǔ)言本身,而你在讀過(guò)本書(shū)后,也才能了解更多語(yǔ)言方面的細(xì)節(jié)。請(qǐng)務(wù)必明白,這七門(mén)語(yǔ)言,無(wú)論教還是學(xué),對(duì)我們而言都是一個(gè)宏偉目標(biāo)。作為讀者,你的腦袋必須多騰出點(diǎn)地方,以容納七種不同的語(yǔ)法風(fēng)格、四種編程范型、四十年語(yǔ)言開(kāi)發(fā)的寶貴經(jīng)驗(yàn);作為作者,我必須盡量全面地涵蓋各個(gè)主題,以便讓你更好地理解語(yǔ)言。為了寫(xiě)好這本書(shū),我老早就學(xué)過(guò)了這七門(mén)語(yǔ)言中的幾門(mén),但若想完美地兼顧每門(mén)語(yǔ)言所有最重要的細(xì)節(jié),還需要一些化繁為簡(jiǎn)的本事才行。1.4.1超越語(yǔ)法想真正理解語(yǔ)言設(shè)計(jì)者的思路,就必須有超越基本語(yǔ)法的覺(jué)悟。這意味著,你不能僅僅停留在編寫(xiě)“Hello,World”這種普通代碼,甚至斐波那契數(shù)列代碼的水平。如果是Ruby,你得會(huì)寫(xiě)一些元編程代碼;如果是Prolog,你必須會(huì)解決完整的數(shù)獨(dú)問(wèn)題;如果是Erlang,你要懂得如何寫(xiě)一個(gè)監(jiān)控程序,這程序不僅能檢測(cè)崩潰進(jìn)程,還能啟動(dòng)另一進(jìn)程以接替崩潰進(jìn)程的工作,或?qū)⒈罎⑦M(jìn)程的相關(guān)信息告知用戶(hù)。在地帶你超越語(yǔ)法之前,我要先向你作個(gè)承諾,同時(shí)也不得不作個(gè)讓步。承諾是:決不會(huì)淺嘗輒止、敷衍了事;讓步是:無(wú)法像專(zhuān)業(yè)語(yǔ)言書(shū)籍那樣涵蓋所有基礎(chǔ)知識(shí)。我?guī)缀鯖](méi)有涉及異常處理,除非它是哪一門(mén)語(yǔ)言的基本特性;我也沒(méi)有詳細(xì)介紹包模型,因?yàn)槲覀冏龅亩际切№?xiàng)目,沒(méi)有必要用到打包模型;還有,不少原始類(lèi)型(primitive)我也只字未提,因?yàn)榻鉀Q本書(shū)提出的基本問(wèn)題時(shí),用不到的原始類(lèi)型自然不必提到。1.4.2不是安裝指南寫(xiě)這書(shū)最大的挑戰(zhàn)來(lái)自于平臺(tái)。我與各種書(shū)的不少讀者都有過(guò)直接接觸,他們所用的平臺(tái)包括三種Windows平臺(tái)、OSX以及至少五種Unix系統(tǒng)。我也在各大留言板上看過(guò)數(shù)不勝數(shù)的平臺(tái)之爭(zhēng)。把七門(mén)語(yǔ)言安裝到七種平臺(tái)上,這別說(shuō)一位作者,就算多位作者合著,估計(jì)也是無(wú)解難題。我無(wú)意解決七門(mén)語(yǔ)言的安裝問(wèn)題,所以就不費(fèi)那精力去琢磨多平臺(tái)了。我猜你不會(huì)有興趣讀一份老掉牙的安裝指南。語(yǔ)言和平臺(tái)都在不斷發(fā)生變化。我只要告訴你去哪里安裝語(yǔ)言、我用的是什么版本就夠了。這樣你就可以和大家一樣,照著最新的安裝指南去做。一步步地教你安裝語(yǔ)言真沒(méi)什么必要。1.4.3不是編程參考為保證本書(shū)質(zhì)量,我們盡最大努力對(duì)書(shū)中代碼進(jìn)行了審閱,其中一部分還有幸請(qǐng)到了語(yǔ)言設(shè)計(jì)者親自審閱。在經(jīng)歷出版前的層層嚴(yán)格審閱之后,我確信,這些代碼足以深刻闡釋每一門(mén)語(yǔ)言的精髓。不過(guò),當(dāng)你自己試著上手用這七門(mén)語(yǔ)言編程時(shí),我再怎么玩命,也不可能把一份全面的語(yǔ)言參考擺在你面前。請(qǐng)你多多諒解。關(guān)于這點(diǎn),我想拿平時(shí)會(huì)話(huà)所用的語(yǔ)言打個(gè)比方。觀光旅游時(shí)學(xué)到的語(yǔ)言,和作為母語(yǔ)而熟知的語(yǔ)言相去甚遠(yuǎn)。我英語(yǔ)說(shuō)得流暢自然,西班牙語(yǔ)卻磕磕絆絆。還有三門(mén)語(yǔ)言,我也會(huì)說(shuō)若干短語(yǔ)。我能在日本吃飯時(shí)點(diǎn)魚(yú),也能在意大利問(wèn)人找洗手間。但我心知肚明的是,自己非母語(yǔ)的表達(dá)能力實(shí)在有限。說(shuō)到編程,我的BASIC、C、C++、Java、C#、JavaScript、Ruby等幾門(mén)語(yǔ)言都十分熟練。不甚熟練的語(yǔ)言也不少,其中還包括本書(shū)介紹的幾門(mén)語(yǔ)言。說(shuō)老實(shí)話(huà),以我現(xiàn)在的水平,七門(mén)語(yǔ)言中有六門(mén)都不是非常得心應(yīng)手。近五年當(dāng)中,我一直全職編寫(xiě)Ruby代碼,但說(shuō)到其他語(yǔ)言,我是既說(shuō)不出怎么用Io編個(gè)Web服務(wù)器,也說(shuō)不出如何用Erlang編個(gè)數(shù)據(jù)庫(kù)。如果真去寫(xiě)一本這七門(mén)語(yǔ)言的參考大全,那我一定死得很慘。就算從中隨便挑一門(mén)語(yǔ)言寫(xiě)編程指南,也至少會(huì)有咱們這本書(shū)差不多厚。我能提供各種材料,幫你輕松入門(mén);也能帶你體驗(yàn)每門(mén)語(yǔ)言的真實(shí)范例,讓你親眼見(jiàn)識(shí)它們的程序代碼;還能盡量編譯所有代碼,確保它們正常運(yùn)行。但如果你在試驗(yàn)這些語(yǔ)言時(shí),也希望我能提供指導(dǎo),那我真是心有余而力不足。這七門(mén)語(yǔ)言都有非常優(yōu)秀的支持社區(qū),這也是我選擇它們的原因之一。而且在每個(gè)習(xí)題環(huán)節(jié),我還盡量保留了一個(gè)搜索語(yǔ)言相關(guān)資源的問(wèn)題。用意很明顯——讓你學(xué)會(huì)自力更生。1.4.4嚴(yán)格督促本書(shū)為你鋪就的學(xué)習(xí)途徑,較之網(wǎng)上那些20分鐘教程可謂略勝一籌。我知道,你我同為善用Google之人,隨便搜索書(shū)中某門(mén)語(yǔ)言的簡(jiǎn)明教程自是不在話(huà)下。不過(guò)本書(shū)的高明之處在于,它會(huì)帶你踏上快速成長(zhǎng)的互動(dòng)之旅。你每周都會(huì)遇到一些小型的編程挑戰(zhàn)和一個(gè)實(shí)戰(zhàn)項(xiàng)目。解決它們雖非易事,但這既能增長(zhǎng)你的見(jiàn)識(shí),還可讓你體驗(yàn)編程之樂(lè)。如果你閱讀本書(shū)時(shí)不做任何習(xí)題,那不過(guò)是對(duì)語(yǔ)法有了個(gè)粗淺認(rèn)識(shí)。如果你在嘗試獨(dú)立解答習(xí)題之前,先去網(wǎng)上搜索答案,那也一樣意味著不及格。你首先要有試著解答習(xí)題的主觀愿望,同時(shí)也要充分認(rèn)識(shí)到,有一小部分習(xí)題可能超出了你的能力范圍。要知道,學(xué)會(huì)語(yǔ)法永遠(yuǎn)比學(xué)思考簡(jiǎn)單。如果以上描述讓你心驚膽戰(zhàn),我建議你放下這本書(shū),換本別的書(shū)看看。對(duì)你來(lái)說(shuō),也許看七本不同的編程語(yǔ)言書(shū)會(huì)更輕松愜意。但是,如果你馬上想到的是看這本書(shū)所能帶來(lái)的回報(bào)——寫(xiě)出一手更漂亮的代碼——并為此激動(dòng)不已,那就別猶豫了,趕緊往下看吧。1.5最后一擊此時(shí)此刻,我真想對(duì)你說(shuō)幾句意義深遠(yuǎn)又讓人熱血沸騰的話(huà),但千言萬(wàn)語(yǔ)匯成四個(gè)字——享受編程。第2章Ruby有糖相伴好下藥?!狹aryPoppins如果你正信手翻閱此書(shū),那我們大概志趣相投——都喜歡學(xué)習(xí)各種編程語(yǔ)言。對(duì)我來(lái)說(shuō)學(xué)一種語(yǔ)言,就如同了解一個(gè)人的性格一般。自我進(jìn)入編程行業(yè)以來(lái),用過(guò)的語(yǔ)言已不在少數(shù),深知語(yǔ)言如人,每種語(yǔ)言都有其獨(dú)特個(gè)性。Java像一位地主家的孩子,小時(shí)候天真可愛(ài),但長(zhǎng)大后開(kāi)始巧取豪奪,方圓百里之內(nèi)聽(tīng)不到一絲歡聲笑語(yǔ);VisualBasic像一位濃妝艷抹的美發(fā)師,雖對(duì)全球變暖問(wèn)題一無(wú)所知,理發(fā)卻是一把好手,言談風(fēng)趣幽默總能把人逗得開(kāi)懷大笑。在本書(shū)中,我將把你學(xué)到的每門(mén)語(yǔ)言都比作某個(gè)著名的影視人物。希望這樣的比喻能對(duì)你有所啟發(fā),讓你多少明白各語(yǔ)言與眾不同的性格所在。先來(lái)認(rèn)識(shí)一下Ruby,我的最?lèi)?ài)之一。她偶爾會(huì)搞怪,卻總是很嫵媚;帶有那么點(diǎn)神秘,卻有著百分百的魅力。還記得英國(guó)保姆MaryPoppins嗎?她那個(gè)年代,保姆多半像C語(yǔ)言家族的大多數(shù)語(yǔ)言那樣,做什么都很利索,就是沒(méi)什么人情味兒,而且枯燥死板、一成不變。其實(shí),只要一勺糖,一切都會(huì)不同。MaryPoppins從家務(wù)中尋找樂(lè)趣,以責(zé)任感喚起熱情,做起家務(wù)來(lái)自然事半功倍。Ruby所做的也同樣如此,但它用的不是食用糖,而是語(yǔ)法糖。作為Ruby的發(fā)明者,Matz并不擔(dān)心編程語(yǔ)言的執(zhí)行效率,而是把精力放在了提高程序員的編程效率上。2.1Ruby簡(jiǎn)史松本行弘(YukihiroMatsumoto)大約在1993年發(fā)明了Ruby,大家多稱(chēng)他為Matz。從語(yǔ)言的角度看,Ruby出身于所謂的腳本語(yǔ)言家族,是一種解釋型、面向?qū)ο?、?dòng)態(tài)類(lèi)型的語(yǔ)言。解釋型,意味著Ruby代碼由解釋器而非編譯器執(zhí)行。動(dòng)態(tài)類(lèi)型,意味著類(lèi)型在運(yùn)行時(shí)而非編譯時(shí)綁定。從這兩方面看,Ruby采取的策略是在靈活性和運(yùn)行時(shí)安全之間尋找平衡點(diǎn),我們稍后還會(huì)深入討論這一點(diǎn)。面向?qū)ο螅馕吨鳵uby支持封裝(把數(shù)據(jù)和行為一起打包)、類(lèi)繼承(用一棵類(lèi)樹(shù)來(lái)組織對(duì)象類(lèi)型)、多態(tài)(對(duì)象可表現(xiàn)為多種形式)等特性。Ruby多年來(lái)一直默默蟄伏,只為等待一個(gè)恰當(dāng)?shù)某霈F(xiàn)時(shí)機(jī)。終于,隨著Rails框架嶄露頭角,Ruby也在2006年前后一鳴驚人。在企業(yè)開(kāi)發(fā)的叢林中跋涉了十年之后,Ruby指引人們重新找回了編程樂(lè)趣。盡管從執(zhí)行速度上說(shuō),Ruby談不上有多高效,但它卻能讓程序員的編程效率大幅提高。松本行弘訪談錄我很高興來(lái)到松本先生的家鄉(xiāng)——日本松江市拜會(huì)松本先生。我們?cè)谡勗?huà)間聊到一些Ruby語(yǔ)言背后的設(shè)計(jì)思想,松本先生也解答了我向他提出的幾個(gè)問(wèn)題。Bruce:你為什么要開(kāi)發(fā)Ruby?Matz:我從一開(kāi)始擺弄計(jì)算機(jī),就對(duì)編程語(yǔ)言產(chǎn)生了興趣。編程語(yǔ)言不僅是用來(lái)編程的方法,還是思維的放大器,可以塑造思考編程的方式。所以很長(zhǎng)一段時(shí)間,我都把編程語(yǔ)言當(dāng)作一項(xiàng)興趣愛(ài)好,下了不少功夫研究。我甚至實(shí)現(xiàn)了幾門(mén)玩具語(yǔ)言,但都派不上什么用場(chǎng)。1993年,當(dāng)我看到Perl的時(shí)候,不知怎么的,這種混合了Lisp和Smalltalk特征的面向?qū)ο笳Z(yǔ)言讓我的靈感一下子迸發(fā)出來(lái)。我意識(shí)到Perl將成為一門(mén)可提高我們生產(chǎn)力的偉大語(yǔ)言。于是,出于自?shī)首詷?lè)的動(dòng)機(jī),我著手開(kāi)發(fā)一門(mén)與之類(lèi)似的語(yǔ)言,并將其命名為Ruby。剛開(kāi)始的時(shí)候,開(kāi)發(fā)Ruby還純屬業(yè)余愛(ài)好,處處都能按自己的口味設(shè)計(jì)。后來(lái),世界各地的程序員開(kāi)始漸漸接受這門(mén)語(yǔ)言及其背后的設(shè)計(jì)原則。它越來(lái)越受人們喜愛(ài),這遠(yuǎn)遠(yuǎn)超出了我的預(yù)期。Bruce:你最喜歡它哪一點(diǎn)呢?Matz:我喜歡它寓編程于樂(lè)的方式。說(shuō)到某個(gè)具體的技術(shù)點(diǎn),我最喜歡的是“代碼塊”(block)。代碼塊即是一種易于控制的高階函數(shù),也為DSL(Domain-SpecificLanguage,領(lǐng)域特定語(yǔ)言)及其他特性的實(shí)現(xiàn)提供了極大的靈活性。Bruce:如果能讓時(shí)光倒流,你想改變哪些特性?Matz:我想去掉線程,加入actor(參與者)或一些更高級(jí)的并發(fā)特性。無(wú)論你是否已對(duì)Ruby有所了解,都請(qǐng)一邊閱讀本章,一邊留意Matz為設(shè)計(jì)這門(mén)語(yǔ)言所做的種種權(quán)衡。你可以看看他添加了哪些語(yǔ)法糖——那些打破了語(yǔ)言常規(guī),不僅為程序員提供更加友好的體驗(yàn),而且讓代碼更容易理解的小特性。還可以看看Matz在集合(collection)等處用到的代碼塊,體會(huì)一下它們?nèi)绾伟l(fā)揮出夢(mèng)幻般的效果。還有,盡可能去理解他在簡(jiǎn)單性和安全性之間、編碼效率和程序性能之間所做的哪些讓步和折中。這就開(kāi)始吧。先簡(jiǎn)單看看下面這幾行Ruby代碼,找找感覺(jué):>>properties=['objectoriented','ducktyped','productive','fun']=>["objectoriented","ducktyped","productive","fun"]>>properties.each{|property|puts"Rubyis#{property}."}Rubyisobjectoriented.Rubyisducktyped.Rubyisproductive.Rubyisfun.=>["objectoriented","ducktyped","productive","fun"]有了Ruby,我們又能帶著笑容編程了。作為一門(mén)徹頭徹尾的動(dòng)態(tài)語(yǔ)言,它擁有令人驚嘆的社區(qū)支持。它的各種實(shí)現(xiàn)版本都是開(kāi)源的。它的社區(qū)里沒(méi)有其他語(yǔ)言社區(qū)泛濫成災(zāi)的那種華而不實(shí)的框架,因?yàn)槠渖虡I(yè)支持大都來(lái)自于小公司。它雖在企業(yè)應(yīng)用領(lǐng)域勢(shì)頭不顯,但憑借編程效率上的優(yōu)勢(shì),在Web開(kāi)發(fā)等領(lǐng)域可謂如雷貫耳。2.2第一天:找個(gè)保姆且不說(shuō)MaryPoppins會(huì)什么魔法,她首先得是一名優(yōu)秀保姆。當(dāng)你剛上手學(xué)一門(mén)語(yǔ)言時(shí),必須先了解如何用它去完成能用其他語(yǔ)言搞定的事。下面,我們即將開(kāi)始和Ruby的首次接觸。你可以把這當(dāng)作一次彼此交流的機(jī)會(huì)。你們交流起來(lái)是否順暢?有沒(méi)有幾分難以名狀的尷尬?它有什么樣的核心編程模型?采用何種方法處理類(lèi)型?現(xiàn)在,讓我們開(kāi)始尋找答案吧。2.2.1快速起步我承諾過(guò),不會(huì)帶你體驗(yàn)?zāi)欠N婆婆媽媽又老掉牙的安裝過(guò)程。Ruby安裝起來(lái)不過(guò)是小菜一碟。你只需移步/en/downloads/,找到你所用的平臺(tái),安裝Ruby1.8.6或更高版本即可。我在撰寫(xiě)本章時(shí),用的是Ruby1.8.7,而1.9版可能會(huì)有一些細(xì)微差別。如果你用Windows平臺(tái),可下載簡(jiǎn)便易用的一鍵安裝包;如果你用OSXLeopard或更高版本的蘋(píng)果平臺(tái),可在Xcode安裝盤(pán)中找到Ruby。輸入irb可測(cè)試安裝是否成功。如果沒(méi)提示任何錯(cuò)誤,你就放心閱讀本章的剩余部分好了;如果提示錯(cuò)誤,那也沒(méi)什么好怕的,別人可能早就遇到過(guò)類(lèi)似問(wèn)題。只需把錯(cuò)誤信息輸入Google,解決方法可能就會(huì)在你面前出現(xiàn)。2.2.2從命令行執(zhí)行Ruby如果你尚未輸入irb,現(xiàn)在馬上輸入。你會(huì)看到Ruby的交互命令行,其中可輸入命令并獲得反饋。輸入下列命令:>>puts'hello,world'hello,world=>nil>>language='Ruby'=>"Ruby">>puts"hello,#{language}"hello,Ruby=>nil>>language='myRuby'=>"myRuby">>puts"hello,#{language}"hello,myRuby=>nil如果你對(duì)Ruby一無(wú)所知,這短短幾行代碼示例就暗藏了不少線索。第一,它告訴你,Ruby是解釋執(zhí)行的。確切地說(shuō),Ruby幾乎總是解釋執(zhí)行的,但也有開(kāi)發(fā)者正著手開(kāi)發(fā)虛擬機(jī),想把Ruby代碼編譯成字節(jié)碼再執(zhí)行;第二,我沒(méi)在代碼里聲明任何變量;第三,即使我沒(méi)讓Ruby返回任何值,這幾行代碼也都具有各自的返回值。實(shí)際上,每條Ruby代碼都會(huì)返回某個(gè)值。此外,你還至少看見(jiàn)了兩種形式的字符串。單引號(hào)包含的字符串表示它將不加改動(dòng)地直接解釋?zhuān)p引號(hào)包含的字符串則會(huì)引發(fā)字符串替換。字符串替換是Ruby解釋器所做的一種求值。在上面的示例中,Ruby把變量language的返回值替換進(jìn)了字符串。好,繼續(xù)前進(jìn)。2.2.3Ruby的編程模型當(dāng)你新接觸一門(mén)語(yǔ)言的時(shí)候,有些問(wèn)題是需要首先去思考的,“這門(mén)語(yǔ)言的編程模型是什么”正是其中之一。這問(wèn)題有時(shí)不那么好回答。你可能早就接觸過(guò)C、Fortran、Pascal這類(lèi)過(guò)程式語(yǔ)言?,F(xiàn)如今,大部分人在用面向?qū)ο笳Z(yǔ)言,不過(guò)它們大都帶有過(guò)程式語(yǔ)言要素,比如,數(shù)字4在Java中就不是對(duì)象。你也許沖著函數(shù)式編程語(yǔ)言買(mǎi)的這本書(shū)。但某些函數(shù)式語(yǔ)言(如Scala)還加入了一些面向?qū)ο笏枷耄梢哉f(shuō)它們混合了多種編程模型。另外,也有很多其他編程模型?;跅5恼Z(yǔ)言(如PostScript或Forth),使用一個(gè)或多個(gè)棧作為該語(yǔ)言的核心特征?;谶壿嫷恼Z(yǔ)言(如Prolog),是以規(guī)則(rule)為中心建立起來(lái)的。原型語(yǔ)言(如Io、Lua和Self)用對(duì)象而不用類(lèi)來(lái)作為定義對(duì)象甚至繼承的基礎(chǔ)。Ruby是一門(mén)純面向?qū)ο笳Z(yǔ)言。在本章中你將看到,Ruby是如何深入挖掘面向?qū)ο笏枷氲?。先?lái)看一些基本對(duì)象:>>4=>4>>4.class=>Fixnum>>4+4=>8>>4.methods=>["inspect","%","<<","singleton_method_added","numerator",..."*","+","to_i","methods",...]雖然在代碼最后的列表中,我省略了一些方法,但已經(jīng)充分說(shuō)明了問(wèn)題。在Ruby中,一切皆為對(duì)象,就連每個(gè)單獨(dú)的數(shù)字也不例外。通過(guò)此例,我們可以看出,數(shù)字是Fixnum類(lèi)型的對(duì)象,且調(diào)用methods方法可返回方法數(shù)組(Ruby用方括號(hào)表示數(shù)組)。實(shí)際上,我們可以用“.”符號(hào)調(diào)用對(duì)象具有的任意方法。2.2.4判斷程序編出來(lái)是用于判斷決策的,因此在編程語(yǔ)言中,如何使用判斷也就理所當(dāng)然成為其核心思想,它影響我們用這門(mén)語(yǔ)言編碼和思維的方式。Ruby的判斷語(yǔ)句和其他大部分面向?qū)ο蠡蜻^(guò)程式語(yǔ)言大同小異。看看下面的表達(dá)式:>>x=4=>4>>x<5=>true>>x<=4=>true>>x>4=>false>>false.class=>FalseClass>>true.class=>TrueClass也就是說(shuō),Ruby中有取值為true或false的表達(dá)式。和其他語(yǔ)言一樣,Ruby中的true和false也是一等對(duì)象(first-classobject)。它們可用來(lái)執(zhí)行下列涉及條件判斷的代碼:>>x=4=>4>>puts'Thisappearstobefalse.'unlessx==4=>nil>>puts'Thisappearstobetrue.'ifx==4Thisappearstobetrue.=>nil>>ifx==4>>puts'Thisappearstobetrue.'>>endThisappearstobetrue.=>nil>>unlessx==4>>puts'Thisappearstobefalse.'>>else?>puts'Thisappearstobetrue.'>>endThisappearstobetrue.=>nil>>puts'Thisappearstobetrue.'ifnottrue=>nil>>puts'Thisappearstobetrue.'if!true=>nil我非常喜歡Ruby的這種設(shè)計(jì),它把條件句變得簡(jiǎn)單明了。當(dāng)你使用if或unless時(shí),既可選用塊形式(ifcondition,statements,end),也可選用單行形式(statementsifcondition)。也許在某些人看來(lái),if的單行形式令人作嘔,但我卻覺(jué)得,它僅僅用了一行代碼,就清楚地表達(dá)了思想:order.calculate_taxunlessorder.nil?當(dāng)然,你也可以用塊形式寫(xiě)這行代碼,但這樣做會(huì)在本應(yīng)單純、連貫的思想中引入一些不必要的干擾。把簡(jiǎn)單的想法精煉到短短一行代碼之中,別人讀起來(lái)會(huì)輕松許多。此外,我還對(duì)unless頗為欣賞。你可以用not或!表達(dá)同樣意圖,但用unless表達(dá)要好得多。while和until亦是如此:>>x=x+1whilex<10=>nil>>x=>10>>x=x-1untilx==1=>nil>>x=>1>>whilex<10>>x=x+1>>putsx>>end2345678910=>nil注意,=用于賦值,而==用于判斷是否相等。在Ruby中,每種對(duì)象都有自己特有的相等概念。數(shù)字對(duì)象的值相等時(shí),它們相等。你也可以用true和false之外的值作為表達(dá)式:>>puts'Thisappearstobetrue.'if1Thisappearstobetrue.=>nil>>puts'Thisappearstobetrue.'if'randomstring'(irb):31:warning:stringliteralinconditionThisappearstobetrue.=>nil>>puts'Thisappearstobetrue.'if0Thisappearstobetrue.=>nil>>puts'Thisappearstobetrue.'iftrueThisappearstobetrue.=>nil>>puts'Thisappearstobetrue.'iffalse=>nil>>puts'Thisappearstobetrue.'ifnil=>nil也就是說(shuō),除了nil和false之外,其他值都代表true。C和C++程序員可得小心了,0也是true!Ruby的邏輯運(yùn)算符,跟C、C++、C#、Java差不多,但也稍有不同。and(也可寫(xiě)為&&)是邏輯與,or(也可寫(xiě)為||)是邏輯或。用這兩種運(yùn)算符驗(yàn)證表達(dá)式時(shí),一旦表達(dá)式的值已能明確求出,解釋器就不再繼續(xù)執(zhí)行后面的表達(dá)式代碼。如果想執(zhí)行整個(gè)表達(dá)式的話(huà),可以用&或|進(jìn)行比較。下面,看看它們是如何運(yùn)行的:>>trueandfalse=>false>>trueorfalse=>true>>false&&false=>false>>true&&this_will_cause_an_errorNameError:undefinedlocalvariableormethod`this_will_cause_an_error'formain:Objectfrom(irb):59>>false&&this_will_not_cause_an_error=>false>>trueorthis_will_not_cause_an_error=>true>>true||this_will_not_cause_an_error=>true>>true|this_will_cause_an_errorNameError:undefinedlocalvariableormethod`this_will_cause_an_error'formain:Objectfrom(irb):2from:0>>true|false=>true這段代碼可謂一目了然,不必多加解釋。我們一般會(huì)使用邏輯運(yùn)算符的短路版本。2.2.5鴨子類(lèi)型接下來(lái),我們學(xué)一點(diǎn)有關(guān)Ruby類(lèi)型模型的內(nèi)容。首先,你必須知道,當(dāng)你錯(cuò)誤使用類(lèi)型時(shí),Ruby能在多大程度上給予保護(hù)。這里說(shuō)的就是類(lèi)型安全(typesafety)。強(qiáng)類(lèi)型語(yǔ)言會(huì)對(duì)某些操作進(jìn)行類(lèi)型檢查,并在其造成破壞前加以阻止。當(dāng)你把代碼提交給解釋器或編譯器,或是執(zhí)行代碼時(shí),就會(huì)進(jìn)行類(lèi)型檢查??纯聪旅娴拇a:>>4+'four'TypeError:Stringcan'tbecoercedintoFixnumfrom(irb):51:in`+'from(irb):51>>4.class=>Fixnum>>(4.0).class=>Float>>4+4.0=>8.0由此可見(jiàn),Ruby是強(qiáng)類(lèi)型語(yǔ)言,這意味著發(fā)生類(lèi)型沖突時(shí),你將得到一個(gè)錯(cuò)誤。另外,Ruby是在運(yùn)行時(shí)而非編譯時(shí)進(jìn)行類(lèi)型檢查的。為了證明這一點(diǎn),我打算比原計(jì)劃提前一些介紹定義函數(shù)的方法。關(guān)鍵字def定義一個(gè)函數(shù),但不會(huì)執(zhí)行它。輸入下列代碼:>>defadd_them_up>>4+'four'>>end=>nil>>add_them_upTypeError:Stringcan'tbecoercedintoFixnumfrom(irb):56:in`+'from(irb):56:in`add_them_up'from(irb):58所以說(shuō),直到真正嘗試執(zhí)行代碼時(shí),Ruby才進(jìn)行類(lèi)型檢查。這一概念稱(chēng)做動(dòng)態(tài)類(lèi)型。在采用靜態(tài)類(lèi)型系統(tǒng)的情況下,編譯器和工具能捕獲更多錯(cuò)誤,因此Ruby不會(huì)像靜態(tài)類(lèi)型語(yǔ)言捕獲的錯(cuò)誤那么多。這是它的劣勢(shì)。但Ruby的類(lèi)型系統(tǒng)也有自己的潛在優(yōu)勢(shì),即多個(gè)類(lèi)不必繼承自相同父類(lèi),就能以相同方式使用:>>i=0=>0>>a=['100',100.0]=>['100',100.0]>>whilei<2>>putsa[i].to_i>>i=i+1>>end100100剛才你看到的就是我們實(shí)際應(yīng)用中常見(jiàn)的鴨子類(lèi)型(ducktyping)。這數(shù)組的第一個(gè)元素是String,第二個(gè)元素是Float,而把它們轉(zhuǎn)換成整數(shù)的代碼,卻都用的是to_i。鴨子類(lèi)型并不在乎其內(nèi)在類(lèi)型可能是什么。只要它像鴨子一樣走路,像鴨子一樣嘎嘎叫,那它就是只鴨子。在這個(gè)例子中,to_i就相當(dāng)于嘎嘎叫。對(duì)于面向?qū)ο笤O(shè)計(jì)的清晰性來(lái)說(shuō),鴨子類(lèi)型至關(guān)重要。在面向?qū)ο笤O(shè)計(jì)思想中,有這樣一個(gè)重要原則:對(duì)接口編碼,不對(duì)實(shí)現(xiàn)編碼。如果利用鴨子類(lèi)型,實(shí)現(xiàn)這一原則只需極少的額外工作,輕輕松松就能完成。舉個(gè)例子,對(duì)象若有push和pop方法,它就能當(dāng)作棧來(lái)用;反之若沒(méi)有,就不能當(dāng)作棧。2.2.6第一天我們學(xué)到了什么學(xué)到這里,我們才好不容易把基礎(chǔ)知識(shí)都過(guò)了一遍。Ruby是一門(mén)解釋型語(yǔ)言。一切皆為對(duì)象,且易于獲取對(duì)象的任何信息,如對(duì)象的各方法及所屬類(lèi)。它是鴨子類(lèi)型的,且行為通常和強(qiáng)類(lèi)型語(yǔ)言毫無(wú)二致,盡管一些學(xué)者會(huì)爭(zhēng)論其中差別。它也是崇尚自由精神的語(yǔ)言,允許你做幾乎一切事情,包括修改NilClass或String這樣的核心類(lèi)?,F(xiàn)在,讓我們放松一下,做一些自習(xí)。2.2.7第一天自習(xí)你已經(jīng)結(jié)束了和Ruby的首次約會(huì),接下來(lái)該寫(xiě)寫(xiě)代碼了。在這一階段,你不必寫(xiě)出完整的程序,用irb執(zhí)行Ruby語(yǔ)句就行。找?RubyAPI文檔。?ProgrammingRuby:ThePragmaticProgrammer’sGuide[TFH08]的免費(fèi)在線版本。?替換字符串某一部分的方法。?有關(guān)Ruby正則表達(dá)式的資料。?有關(guān)Ruby區(qū)間(range)的資料。做?打印字符串"Hello,world."。?在字符串"Hello,Ruby."中,找出"Ruby."所在下標(biāo)。?打印你的名字十遍。?打印字符串"Thisissentencenumber1.",其中的數(shù)字1會(huì)一直變化到10。?從文件運(yùn)行Ruby程序。?加分題:如果你感覺(jué)意猶未盡,還可以寫(xiě)一個(gè)選隨機(jī)數(shù)的程序。該程序讓玩家猜隨機(jī)數(shù)是多少,并告訴玩家是猜大了還是猜小了。(提示:rand(10)可產(chǎn)生0~9的隨機(jī)數(shù),gets可讀取鍵盤(pán)輸入的字符串,你要把輸入字符串轉(zhuǎn)換成整數(shù)。)2.3第二天:從天而降想當(dāng)年,MaryPoppins撐著傘、翩然降落于小鎮(zhèn)的登場(chǎng)方式,絕對(duì)是那部電影最讓人心馳目眩的一幕。要是擱現(xiàn)在,我的小孩才不會(huì)理解這樣登場(chǎng)有什么好大驚小怪的。第二天中,你會(huì)親身體驗(yàn)令Ruby大受歡迎的小魔法。你將學(xué)習(xí)對(duì)象、集合、類(lèi)等基本構(gòu)建單元的用法,還將學(xué)到代碼塊的基本要素。做好準(zhǔn)備、睜大眼睛,見(jiàn)識(shí)一下這些小魔法吧。2.3.1定義函數(shù)和Java、C#不同,你不必為了定義函數(shù)而把整個(gè)類(lèi)都構(gòu)建出來(lái)。用命令行就可以定義函數(shù):>>deftell_the_truth>>true>>end每個(gè)函數(shù)都會(huì)返回結(jié)果。如果你沒(méi)有顯式指定某個(gè)返回值,函數(shù)就將返回退出函數(shù)前最后處理的表達(dá)式的值。像所有其他事物一樣,函數(shù)也是個(gè)對(duì)象。我們稍后會(huì)討論如何把函數(shù)作為參數(shù)傳遞給其他函數(shù)。2.3.2數(shù)組數(shù)組是Ruby有序集合中的主力部隊(duì)。雖說(shuō)Ruby1.9新引入了有序散列表,但總的來(lái)看,數(shù)組仍是Ruby最重要的有序集合??纯聪旅孢@段代碼:>>animals=['lions','tigers','bears']=>["lions","tigers","bears"]>>putsanimalslionstigersbears=>nil>>animals[0]=>"lions">>animals[2]=>"bears">>animals[10]=>nil>>animals[-1]=>"bears">>animals[-2]=>"tigers">>animals[0..1]=>['lions','tigers']>>(0..1).class=>Range可以看到,Ruby的集合提供了一定的靈活性。如果訪問(wèn)任何未定義的數(shù)組元素,Ruby會(huì)直接返回nil。你也能發(fā)現(xiàn)一些不會(huì)讓數(shù)組功能更強(qiáng),但會(huì)讓它更簡(jiǎn)便易用的特性。比如,animals[-1]返回倒數(shù)第一個(gè)元素,animals[-2]返回倒數(shù)第二個(gè)元素,以此類(lèi)推。這樣為了便于使用而添加的特性就是語(yǔ)法糖。表達(dá)式animals[0..1]看似有幾分像語(yǔ)法糖,但其實(shí)不是。0..1是個(gè)Range(區(qū)間)對(duì)象,表示從0到1(包括0和1)的所有數(shù)字。數(shù)組也可容納其他類(lèi)型的元素:>>a[0]=0NameError:undefinedlocalvariableormethod`a'formain:Objectfrom(irb):23>>a=[]=>[]啊,a現(xiàn)在還不是數(shù)組呢,我就把它當(dāng)成數(shù)組來(lái)用了。這錯(cuò)誤也提示我們,Ruby的數(shù)組和散列表的運(yùn)行方式。實(shí)際上,[]是Array類(lèi)的方法:>>[1].class=>Array>>[1].methods.include?('[]')=>true>>#use[1].methods.include?(:[])onruby1.9這樣看來(lái),[]和[]=不過(guò)是訪問(wèn)數(shù)組的語(yǔ)法糖而已。想正確使用它們,必須先在變量里放一個(gè)空數(shù)組,然后就能像下面這樣操作變量:>>a[0]='zero'=>"zero">>a[1]=1=>1>>a[2]=['two','things']=>["two","things"]>>a=>["zero",1,["two","things"]]從上面代碼還可看出,數(shù)組元素不必具有相同類(lèi)型。>>a=[[1,2,3],[10,20,30],[40,50,60]]=>[[1,2,3],[10,20,30],[40,50,60]]>>a[0][0]=>1>>a[1][2]=>30多維數(shù)組也不過(guò)是數(shù)組的數(shù)組而已。>>a=[1]=>[1]>>a.push(1)=>[1,1]>>a=[1]=>[1]>>a.push(2)=>[1,2]>>a.pop=>2>>a.pop=>1數(shù)組擁有極其豐富的API,可將其用作隊(duì)列、鏈表、棧、集合,等等?,F(xiàn)在,我們來(lái)看看Ruby的另一個(gè)主要集合——散列表。2.3.3散列表記住,集合里面就是一個(gè)個(gè)用來(lái)存儲(chǔ)對(duì)象的桶。在散列表的桶里,每個(gè)對(duì)象上都貼著一張標(biāo)簽。這標(biāo)簽就是鍵,而對(duì)象就是鍵所對(duì)應(yīng)的值。散列表就是一串這樣的鍵—值對(duì):>>numbers={1=>'one',2=>'two'}=>{1=>"one",2=>"two"}>>numbers[1]=>"one">>numbers[2]=>"two">>stuff={:array=>[1,2,3],:string=>'Hi,mom!'}=>{:array=>[1,2,3],:string=>"Hi,mom!"}>>stuff[:string]=>"Hi,mom!"這段代碼不算太復(fù)雜。散列表的運(yùn)行機(jī)制很像數(shù)組,但不一定是整數(shù)下標(biāo),而是可以有任意類(lèi)型的鍵。最后那個(gè)散列表很有趣,因?yàn)槲以谄渲惺状我肓朔?hào)(symbol)。符號(hào)是前面帶有冒號(hào)的標(biāo)識(shí)符,類(lèi)似于:symbol的形式。它在給事物和概念命名時(shí)非常好用。盡管兩個(gè)同值字符串在物理上不同,但相同的符號(hào)卻是同一物理對(duì)象。我們可通過(guò)多次獲取相同的符號(hào)對(duì)象標(biāo)識(shí)符來(lái)證實(shí)這一點(diǎn),像下面這樣:>>'string'.object_id=>3092010>>'string'.object_id=>3089690>>:string.object_id=>69618>>:string.object_id=>69618散列表有一些別出心裁的應(yīng)用。比如,Ruby雖然不支持命名參數(shù),但可以用散列表來(lái)模擬它。只要加進(jìn)一顆小小的語(yǔ)法糖,你就能獲得一些有趣的特性:>>deftell_the_truth(options={})>>ifoptions[:profession]==:lawyer>>'itcouldbebelievedthatthisisalmostcertainlynotfalse.'>>else>>true>>end>>end=>nil>>tell_the_truth=>true>>tell_the_truth:profession=>:lawyer=>"itcouldbebelievedthatthisisalmostcertainlynotfalse."該方法帶一個(gè)可選參數(shù)。如果不傳入該參數(shù),options將設(shè)為空散列表,但如果傳入:profession=>為:lawyer,返回結(jié)果就有所不同。它不會(huì)返回true,但因?yàn)镽uby的求值機(jī)制將字符串也當(dāng)作true處理,所以這和返回true幾乎毫無(wú)差別。還需注意,這里的散列表不必用大括號(hào)括起來(lái),因?yàn)閷⑸⒘斜碛米骱瘮?shù)的最后一個(gè)參數(shù)時(shí),大括號(hào)可有可無(wú)。按理說(shuō),既然數(shù)組元素、散列表鍵、散列表值幾乎可以任選類(lèi)型,那么我們就能用Ruby構(gòu)造出極為精妙的數(shù)據(jù)結(jié)構(gòu)。然而,想真正做到這一點(diǎn),還得先學(xué)會(huì)代碼塊才行。2.3.4代碼塊和yield代碼塊是沒(méi)有名字的函數(shù)。它可以作為參數(shù)傳遞給函數(shù)或方法,比如:>>3.times{puts'hiyathere,kiddo'}hiyathere,kiddohiyathere,kiddohiyathere,kiddo大括號(hào)之間的代碼就稱(chēng)作代碼塊。times是Fixnum類(lèi)的方法,它會(huì)執(zhí)行n次x,其中x是代碼塊,n是Fixnum對(duì)象的值。可以采用{/}或do/end兩種界定代碼塊的形式,Ruby的一般慣例是:代碼塊只占一行時(shí)用大括號(hào),代碼塊占多行時(shí)用do/end。代碼塊可帶有一個(gè)或多個(gè)參數(shù):>>animals=['lionsand','tigersand','bears','ohmy']=>["lionsand","tigersand","bears","ohmy"]>>animals.each{|a|putsa}lionsandtigersandbearsohmy上面這段代碼能讓你見(jiàn)識(shí)到代碼塊的威力,它指示Ruby在集合的每個(gè)元素上執(zhí)行某些行為。僅僅用上少許代碼塊語(yǔ)句,Ruby就遍歷了每一個(gè)元素,還把它們?nèi)即蛴×顺鰜?lái)。想親手實(shí)踐一下如何做到這點(diǎn)嗎?看看以下自定義實(shí)現(xiàn)的times方法:>>classFixnum>>defmy_times>>i=self>>whilei>0>>i=i-1>>yield>>end>>end>>end=>nil>>3.my_times{puts'mangymoose'}mangymoosemangymoosemangymoose這段代碼打開(kāi)一個(gè)現(xiàn)有的類(lèi),并向其中添加一個(gè)方法。此例中,添加的方法是my_times,它用yield調(diào)用代碼塊,并循環(huán)某個(gè)給定次數(shù)。代碼塊還可用作一等參數(shù)(first-classparameter),看看下面的例子:>>defcall_block(&block)>>block.call>>end=>nil>>defpass_block(&block)>>call_block(&block)>>end=>nil>>pass_block{puts'Hello,block'}Hello,block這技術(shù)能讓你把可執(zhí)行代碼派發(fā)給其他方法。在Ruby中,代碼塊不僅可用于循環(huán),還可用于延遲執(zhí)行:execute_at_noon{puts'Beepbeep...timetogetup'}執(zhí)行某些條件行為:...somecode...in_case_of_emergencydouse_credit_cardpanicenddefin_case_of_emergencyyieldifemergency?end...morecode...強(qiáng)制實(shí)施某種策略:within_a_transactiondothings_thatmust_happen_togetherenddefwithin_a_transactionbegin_transactionyieldend_transactionend以及諸多其他用途。你會(huì)見(jiàn)到各種使用代碼塊的Ruby庫(kù),包括處理文件的每一行,執(zhí)行HTTP事務(wù)中的任務(wù),在集合上進(jìn)行各種復(fù)雜操作等。Ruby簡(jiǎn)直就是個(gè)代碼塊的大聯(lián)歡。從文件中運(yùn)行Ruby隨著代碼示例越來(lái)越復(fù)雜,用交互命令行運(yùn)行代碼也越來(lái)越麻煩。命令行研究少量代碼尚可,但多數(shù)情況下,還是把代碼放入文件為好。創(chuàng)建一個(gè)名為hello.rb的文件,其中包含任意你想執(zhí)行的Ruby代碼,比如:puts'hello,world'把文件保存到當(dāng)前文件夾,然后從命令行執(zhí)行以下命令:batate$rubyhello.rbhello,world集成開(kāi)發(fā)環(huán)境(integrateddevelopmentenvironment,IDE)雖然功能完善,但用它開(kāi)發(fā)Ruby程序的人很少,大多數(shù)人還是樂(lè)于使用簡(jiǎn)便易用的文件編輯器。我最喜歡的編輯器是TextMate,包括vi、emacs在內(nèi)的眾多熱門(mén)編輯器也都擁有Ruby插件。在你熟練掌握用文件運(yùn)行Ruby程序之后,我們開(kāi)始研究Ruby程序的可復(fù)用組件。2.3.5定義類(lèi)Ruby和Java、C#、C++一樣,也有類(lèi)和對(duì)象。想想餅干模板和餅干,類(lèi)就是對(duì)象的模板。當(dāng)然,Ruby也支持繼承,但和C++不同,Ruby中的類(lèi)只能繼承自一個(gè)叫做超類(lèi)的類(lèi)。耳聽(tīng)為虛眼見(jiàn)為實(shí),打開(kāi)命令行,輸入下列代碼:>>4.class=>Fixnum>>4.class.superclass=>Integer>>4.class.superclass.superclass=>Numeric>>4.class.superclass.superclass.superclass=>Object>>4.class.superclass.superclass.superclass.superclass=>nil到目前為止,還沒(méi)有什么難以理解的內(nèi)容。對(duì)象是從類(lèi)派生出來(lái)的。4的類(lèi)是Fixnum,F(xiàn)ixnum繼承自Integer,而Integer又繼承自Numeric,最終,Numeric繼承自O(shè)bject??匆幌聢D2-1,它展示了這些事物是如何搭配在一起的。所有的事物,歸根結(jié)底都繼承自O(shè)bject。一個(gè)Class同時(shí)也是一個(gè)Module。Class的實(shí)例將作為對(duì)象的模板。在我們的例子中,F(xiàn)ixnum是Class的一個(gè)實(shí)例,而4又是Fixnum的一個(gè)實(shí)例。每一個(gè)類(lèi)同時(shí)也是一個(gè)對(duì)象。>>4.class.class=>Class>>4.class.class.superclass=>Module>>4.class.class.superclass.superclass=>Object圖2-1Ruby元模型如此看來(lái),F(xiàn)ixnum派生自Class類(lèi)。從這里開(kāi)始,你可能會(huì)有些費(fèi)解。Class繼承自Module,Module又繼承自O(shè)bject,說(shuō)到底,Ruby中的一切事物都有一個(gè)共同祖先——Object。ruby/tree.rbclassTreeattr_accessor:children,:node_namedefinitialize(name,children=[])@children=children@node_name=nameenddefvisit_all(&block)visit&blockchildren.each{|c|c.visit_all&block}enddefvisit(&block)block.callselfendendruby_tree=Tree.new("Ruby",[Tree.new("Reia"),Tree.new("MacRuby")])puts"Visitinganode"ruby_tree.visit{|node|putsnode.node_name}putsputs"visitingentiretree"ruby_tree.visit_all{|node|putsnode.node_name}這個(gè)類(lèi)用各種強(qiáng)大特性實(shí)現(xiàn)了一棵非常簡(jiǎn)單的樹(shù)。它有三個(gè)方法:initialize、visit和visit_all,還有兩個(gè)實(shí)例變量:children和node_name。initialize方法有特殊含義,類(lèi)在初始化一個(gè)新對(duì)象的時(shí)候,會(huì)調(diào)用這個(gè)方法。在這里,我有必要指出Ruby的一些慣例和規(guī)則。類(lèi)應(yīng)以大寫(xiě)字母開(kāi)頭,并且一般采用駱駝命名法,如CamelCase。實(shí)例變量(一個(gè)對(duì)象有一個(gè)值)前必須加上@,而類(lèi)變量(一個(gè)類(lèi)有一個(gè)值)前必須加上@@。實(shí)例變量和方法名以小寫(xiě)字母開(kāi)頭,并采用下劃線命名法,如underscore_style。常量采用全大寫(xiě)形式,如ALL_CAPS。前面那段代碼定義了一個(gè)樹(shù)類(lèi)。每棵樹(shù)都有兩個(gè)實(shí)例變量:@children和@node_name。用于邏輯測(cè)試的函數(shù)和方法一般要加上問(wèn)號(hào),如iftest?。attr關(guān)鍵字可用來(lái)定義實(shí)例變量。它有幾種版本,其中最常用的版本是attr和attr_accessor。attr定義實(shí)例變量和訪問(wèn)變量的同名方法,而attr_accessor定義實(shí)例變量、訪問(wèn)方法和設(shè)置方法。前面那段程序真是塞進(jìn)了不少東西,因此有些難以理解。它利用代碼塊和遞歸,使用戶(hù)能訪問(wèn)樹(shù)中所有節(jié)點(diǎn)。每個(gè)Tree類(lèi)的實(shí)例都帶有一個(gè)節(jié)點(diǎn)。initialize方法設(shè)置了children和node_name的初始值。visit方法調(diào)用傳入的代碼塊。visit_all方法先對(duì)當(dāng)前節(jié)點(diǎn)調(diào)用visit方法,然后對(duì)每個(gè)子節(jié)點(diǎn)遞歸調(diào)用visit_all方法。類(lèi)代碼后面的剩余代碼都用到了該類(lèi)的API,先是定義一棵樹(shù),然后訪問(wèn)樹(shù)中的一個(gè)節(jié)點(diǎn),最后訪問(wèn)所有樹(shù)節(jié)點(diǎn)。這產(chǎn)生了以下輸出:VisitinganodeRubyvisitingentiretreeRubyReiaMacRuby類(lèi)只是Ruby的諸多復(fù)雜概念之一。你在閱讀圖2-1上面的那段代碼時(shí),可能瞥見(jiàn)過(guò)模塊(module)這個(gè)詞?,F(xiàn)在,讓我們回過(guò)頭去,仔細(xì)琢磨一下模塊的概念。2.3.6編寫(xiě)Mixin面向?qū)ο笳Z(yǔ)言利用繼承,將行為傳播到相似的對(duì)象上。但對(duì)象若想繼承并不相似的多種行為,一方面可通過(guò)允許從多個(gè)類(lèi)繼承(多繼承)而實(shí)現(xiàn),另一方面也可借助于其他解決方案。過(guò)往經(jīng)驗(yàn)表明,多繼承不僅復(fù)雜,且問(wèn)題多多。Java采用接口解決這一問(wèn)題,而Ruby采用的是模塊。模塊是函數(shù)和常量的集合。如果在類(lèi)中包含了一個(gè)模塊,那么該模塊的行為和常量也會(huì)成為類(lèi)的一部分。通過(guò)下面這個(gè)類(lèi),我們可以把to_f方法添加到任意一個(gè)類(lèi)上:ruby/to_file.rbmoduleToFiledeffilename"object_#{self.object_id}.txt"enddefto_fFile.open(filename,'w'){|f|f.write(to_s)}endendclassPersonincludeToFileattr_accessor:namedefinitialize(name)@name=nameenddefto_snameendendPerson.new('matz').to_f代碼一開(kāi)始是模塊定義。它定義了兩個(gè)方法:to_f方法把to_s方法的輸出寫(xiě)入文件,filename方法提供了寫(xiě)入文件的文件名。這里有件事很有趣:to_s在模塊中使用,在類(lèi)中實(shí)現(xiàn),但定義模塊的時(shí)候,實(shí)現(xiàn)它的類(lèi)甚至還沒(méi)有定義!這說(shuō)明模塊與包含它的類(lèi)之間,是以一種相當(dāng)隱秘的方式相互

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論