国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

?? ??? ??
Ruby用戶指南 3、開始 4、簡(jiǎn)單的例子 5、字符串 6、正則表達(dá)式 7、數(shù)組 8、回到那些簡(jiǎn)單的例子 9、流程控制 10、迭代器 11、面向?qū)ο笏季S 12、方法 13、類 14、繼承 15、重載方法 16、訪問(wèn)控制 17、單態(tài)方法 18、模塊 19、過(guò)程對(duì)象 20、變量 21、全局變量 22、實(shí)變量 23、局部變量 24、類常量 25、異常處理:rescue 26、異常處理:ensure 27、存取器 28、對(duì)象的初始化 29、雜項(xiàng) RGSS入門教程 1、什么是RGSS 2、開始:最簡(jiǎn)單的腳本 3、數(shù)據(jù)類型:數(shù)字 4、數(shù)據(jù)類型:常量與變量 5、數(shù)據(jù)類型:字符串 6、控制語(yǔ)句:條件分歧語(yǔ)句 7、控制語(yǔ)句:循環(huán) 8、函數(shù) 9、對(duì)象與類 10、顯示圖片 11、數(shù)組 12、哈希表(關(guān)聯(lián)數(shù)組) 13、類 14、數(shù)據(jù)庫(kù) 15、游戲?qū)ο?/a> 16、精靈的管理 17、窗口的管理 18、活動(dòng)指令 19、場(chǎng)景類 Programming Ruby的翻譯 Programming Ruby: The Pragmatic Programmer's Guide 前言 Roadmap Ruby.new 類,對(duì)象和變量 容器Containers,塊Blocks和迭代Iterators 標(biāo)準(zhǔn)類型 深入方法 表達(dá)式Expressions 異常,捕捉和拋出(已經(jīng)開始,by jellen) 模塊 基本輸入輸出 線程和進(jìn)程 當(dāng)遭遇挫折 Ruby和它的世界 Ruby和Web開發(fā) Ruby Tk Ruby 和微軟的 Windows 擴(kuò)展Ruby Ruby語(yǔ)言 (by jellen) 類和對(duì)象 (by jellen) Ruby安全 反射Reflection 內(nèi)建類和方法 標(biāo)準(zhǔn)庫(kù) OO設(shè)計(jì) 網(wǎng)絡(luò)和Web庫(kù) Windows支持 內(nèi)嵌文檔 交互式Ruby Shell 支持 Ruby參考手冊(cè) Ruby首頁(yè) 卷首語(yǔ) Ruby的啟動(dòng) 環(huán)境變量 對(duì)象 執(zhí)行 結(jié)束時(shí)的相關(guān)處理 線程 安全模型 正則表達(dá)式 字句構(gòu)造 程序 變量和常數(shù) 字面值 操作符表達(dá)式 控制結(jié)構(gòu) 方法調(diào)用 類/方法的定義 內(nèi)部函數(shù) 內(nèi)部變量 內(nèi)部常數(shù) 內(nèi)部類/模塊/異常類 附加庫(kù) Ruby變更記錄 ruby 1.6 特性 ruby 1.7 特性 Ruby術(shù)語(yǔ)集 Ruby的運(yùn)行平臺(tái) pack模板字符串 sprintf格式 Marshal格式 Ruby FAQ Ruby的陷阱
??

表達(dá)式(Expressions)



到目前為止我們已經(jīng)用了一些基本的表達(dá)式,畢竟,a=b+c是最基本的了,你即使不看本章,也能寫出一大堆的Ruby代碼來(lái)。但是那樣做不是什么有趣的事情;-)。

Ruby和其它語(yǔ)言的一個(gè)不同之處就是任何東西都能返回一個(gè)值,幾乎所有的東西都是表達(dá)式,在實(shí)際中,這有什么意義呢?

一些明顯得作用是可以實(shí)現(xiàn)鏈?zhǔn)秸Z(yǔ)句:

a?=?b?=?c?=?0 ? 0
[?3,?1,?7,?0?].sort.reverse ? [7,?3,?1,?0]

一些不太起眼的東西,比如C和JAVA中的語(yǔ)句,在Ruby中都是表達(dá)式,例如,if和case都返回一個(gè)值,這個(gè)值就是這些語(yǔ)句中最后執(zhí)行的那行。

songType?=?if?song.mp3Type?==?MP3::Jazz
?????????????if?song.written?<?Date.new(1935,?1,?1)
???????????????Song::TradJazz
?????????????else
???????????????Song::Jazz
?????????????end
???????????else
?????????????Song::Other
???????????end



?rating?=?case?votesCast    
??????????when?0...10????then?Rating::SkipThisOne    
??????????when?10...50???then?Rating::CouldDoBetter    
??????????else????????????????Rating::Rave    
??????????end

操作表達(dá)式(Operator Expressions)

Ruby提供了諸如加減乘除等一些操作符,完整的操作符列表和優(yōu)先級(jí)在第18章有列表。

在Ruby中,很多操作符就是對(duì)一些方法的調(diào)用。比如你執(zhí)行a*b+c,實(shí)際上就是調(diào)用對(duì)象a的乘方法,把b作為一個(gè)參數(shù)傳遞過(guò)去,然后在調(diào)用這個(gè)結(jié)果對(duì)象的加方法,把c作為參數(shù)傳遞,實(shí)際上等于:

(a.*(b)).+(c)

因?yàn)槟憧梢灾匦露x實(shí)例方法,所以你可以修改一些不能滿足你的需求的方法,讓它達(dá)到你需要的作用

class?Fixnum
??alias?oldPlus?+
??def?+(other)
????oldPlus(other).succ
??end
end
1?+?2 ? 4
a?=?3
a?+=?4 ? 8

很有用的一個(gè)技巧是你自己寫的的類可以像內(nèi)建對(duì)象一樣參與操作符的操作,比如,我們想從一首歌中間某處開始提取一部分音樂(lè),我們可以用操作符"[ ]"來(lái)完成:

class?Song
??def?[](fromTime,?toTime)
????result?=?Song.new(self.title?+?"?[extract]",
??????????????????????self.artist,
??????????????????????toTime?-?fromTime)
????result.setStartTime(fromTime)
????result
??end
end

這段代碼擴(kuò)展了類Song,增加了[ ]方法,這個(gè)方法接收兩個(gè)參數(shù),一個(gè)開始時(shí)間,一個(gè)結(jié)束時(shí)間。這個(gè)方法返回一個(gè)新的Song對(duì)象,這個(gè)對(duì)象是歌曲的一部分。然后,我們就可以這樣播放這段音樂(lè):

aSong[0,?0.15].play

混合表達(dá)式(Miscellaneous Expressions)

除了上面最普通的操作符表達(dá)式,或者不是很顯眼的語(yǔ)句表達(dá)式(比如if或case),Ruby還支持在表達(dá)式中使用更多的東西。

命令展開 (Command Expansion)

如果你用反引號(hào)(`)來(lái)括起來(lái)一個(gè)字符串,或者用%x{ 和 }括起來(lái),那么這個(gè)表達(dá)式中的字符串默認(rèn)得會(huì)作為底層的操組系統(tǒng)命令來(lái)執(zhí)行,并返回結(jié)果,這個(gè)結(jié)果就是這個(gè)命令在操作系統(tǒng)中執(zhí)行之后的結(jié)果。換行符將不會(huì)從結(jié)果中去掉,所以返回結(jié)果一般都會(huì)包含一個(gè)回車符。

`date` ? "Sun?Jun??9?00:08:26?CDT?2002\n"
`dir`.split[34] ? "lib_singleton.tip"
%x{echo?"Hello?there"} ? "Hello?there\n"

你也可以在命令中使用表達(dá)式展開和所有通常的轉(zhuǎn)義序列。

for?i?in?0..3
??status?=?`dbmanager?status?id=#{i}`
??#?...
end

執(zhí)行的命令的返回狀態(tài)存放在全局變量$?中。

重載反引號(hào)方法

上面我們說(shuō)道,反引號(hào)之中的命令"默認(rèn)"會(huì)作為操作系統(tǒng)命令來(lái)執(zhí)行,實(shí)際上,這個(gè)字符串是傳遞給了 Kernel::` 這個(gè)方法(一個(gè)反引號(hào))來(lái)執(zhí)行。如果你愿意,可以重寫這個(gè)方法,比如如下:

alias?oldBackquote?`
def?`(cmd)
??result?=?oldBackquote(cmd)
??if?$??!=?0
????raise?"Command?#{cmd}?failed"
??end
??result
end
print?`date`
print?`data`
產(chǎn)生:
Sun?Jun??9?00:08:26?CDT?2002
prog.rb:3:?command?not?found:?data
prog.rb:5:in?``':?Command?data?failed?(RuntimeError)
	from?prog.rb:10

賦值

我們前面的例子中都涉及到了賦值這一基本表達(dá)式,下面,我們來(lái)討論一些關(guān)于賦值語(yǔ)句的東西。

一個(gè)賦值語(yǔ)句給一個(gè)變量或者屬性設(shè)定一個(gè)指定的值,變量或?qū)傩栽谧筮?,值在右邊。然后這個(gè)值作為表達(dá)式的返回值返回。也就是說(shuō),我們可以用鏈?zhǔn)劫x值來(lái)給一些變量賦值:

a?=?b?=?1?+?2?+?3
a ? 6
b ? 6
a?=?(b?=?1?+?2)?+?3
a ? 6
b ? 3
File.open(name?=?gets.chomp)

在Ruby中有兩種基本的賦值格式,第一種是指給一個(gè)引用某一參數(shù)或者常量的對(duì)象賦值,這種形式是緊密連接到語(yǔ)言中的。

instrument?=?"piano"
MIDDLE_A???=?440

另一種是在賦值語(yǔ)句左邊使用對(duì)象的屬性或者元素的引用。

aSong.duration????=?234
instrument["ano"]?=?"ccolo"

這種方法比較特殊,通過(guò)調(diào)用左值的方法來(lái)賦值,也就是說(shuō)我們可以重寫這些方法。

我們已經(jīng)看過(guò)如何定義一個(gè)可以修改的屬性了,只需要簡(jiǎn)單的在方法后面以等號(hào)結(jié)尾即可。這個(gè)方法把接收的參數(shù)作為賦值語(yǔ)句的右值。

class?Song
??def?duration=(newDuration)
????@duration?=?newDuration
??end
end

沒(méi)有理由要求這些給參數(shù)設(shè)置值得方法與內(nèi)部的實(shí)例變量一致,或者每個(gè)可以修改的屬性都要提供一個(gè)讀方法,反過(guò)來(lái)也是一樣。

class?Amplifier
??def?volume=(newVolume)
????self.leftChannel?=?self.rightChannel?=?newVolume
??end
??#?...
end

Sidebar:在類中使用訪問(wèn)方法( Accessors)
上面的例子中為什么我們必須要寫 self.leftChannel 而不能省掉self呢?一般的,一個(gè)類中的方法可以直接調(diào)用同類或者父類中的其他方法(默認(rèn)得接收者是self),但是,對(duì)于attribute writers來(lái)說(shuō)這就不管用了,Ruby將把左面的名字作為一個(gè)本地變量,而不是一個(gè)對(duì)寫屬性方法的調(diào)用。

 

class?BrokenAmplifier
??attr_accessor?:leftChannel,?:rightChannel
??def?volume=(vol)
????leftChannel?=?self.rightChannel?=?vol
??end
end
ba?=?BrokenAmplifier.new
ba.leftChannel?=?ba.rightChannel?=?99
ba.volume?=?5
ba.leftChannel ? 99
ba.rightChannel ? 5

我們?cè)?code>leftChannel前面忘了寫self.了,所以ruby把這個(gè)新值賦給了一個(gè)方法volume=的一個(gè)局部變量,而這個(gè)對(duì)象的屬性沒(méi)有任何變化。這可能會(huì)經(jīng)常產(chǎn)生問(wèn)題。

并行賦值

在學(xué)習(xí)了一段時(shí)間程序設(shè)計(jì)之后,我們可能會(huì)遇到要求將兩個(gè)變量的值互換:

int?a?=?1;
int?b?=?2;
int?temp;
temp?=?a; a?=?b; b?=?temp;

在Ruby中很簡(jiǎn)單,只需要:

a,?b?=?b,?a

Ruby可以有效的實(shí)現(xiàn)并行賦值,在右邊的值在被賦給左面的變量或?qū)傩灾鞍凑账鼈兊捻樣嵾M(jìn)行求值,然后對(duì)應(yīng)的賦給左面的屬性或變量。一個(gè)例子如下,第二行給a,b,c的值分別是x,x+=1,x+=1計(jì)算之后的值。

x?=?0 ? 0
a,?b,?c???=???x,?(x?+=?1),?(x?+=?1) ? [0,?1,?2]

當(dāng)一個(gè)賦值語(yǔ)句左值多余一時(shí),這個(gè)表達(dá)式的返回值是一個(gè)由右面的值組成的數(shù)組,如果一個(gè)賦值語(yǔ)句的左值多余右值,多余的左值被設(shè)為nil,反過(guò)來(lái)如果右值多余左值,那么多余的右值將被忽略。在Ruby1.6.2中,如果左值只有一個(gè),右值有多個(gè),那么這些右值將作為一個(gè)數(shù)組賦給左值。

你也可以在并行賦值語(yǔ)句中分解和擴(kuò)展數(shù)組。如果最后的左值以星號(hào)作為前綴,那么所有對(duì)應(yīng)這個(gè)得值和以后的值將會(huì)組成一個(gè)數(shù)組,賦給這個(gè)左值(如下面第三行的c);類似的,如果最后一個(gè)右值是一個(gè)數(shù)組,你可以加一個(gè)星號(hào)作為前綴,Ruby將會(huì)把這個(gè)數(shù)組拆開按相應(yīng)的位置賦給左值(如下面第六行的c,而且,如果這個(gè)數(shù)組是唯一的右值,這個(gè)星號(hào)是可以省略的,作為右值得數(shù)組自動(dòng)拆開,如第二行所示)。

a = [1, 2, 3, 4]
b,??c?=?a ? b == 1, c == 2
b,?*c?=?a ? b == 1, c == [2, 3, 4]
b,??c?=?99,??a ? b == 99, c == [1, 2, 3, 4]
b,?*c?=?99,??a ? b == 99, c == [[1, 2, 3, 4]]
b,??c?=?99,?*a ? b == 99, c == 1
b,?*c?=?99,?*a ? b == 99, c == [1, 2, 3, 4]

嵌套賦值

并行賦值還有一個(gè)值得一提的特性,賦值語(yǔ)句左邊還可以包括用括號(hào)括起來(lái)的變量列表,Ruby中叫做嵌套賦值語(yǔ)句。Ruby首先摘出右值中相應(yīng)的項(xiàng)進(jìn)行賦值,然后在進(jìn)行高層的賦值操作。

b,?(c,?d),?e?=?1,2,3,4 ? b == 1, c == 2, d == nil, e == 3
b,?(c,?d),?e?=?[1,2,3,4] ? b == 1, c == 2, d == nil, e == 3
b,?(c,?d),?e?=?1,[2,3],4 ? b == 1, c == 2, d == 3, e == 4
b,?(c,?d),?e?=?1,[2,3,4],5 ? b == 1, c == 2, d == 3, e == 5
b,?(c,*d),?e?=?1,[2,3,4],5 ? b == 1, c == 2, d == [3, 4], e == 5

其它賦值形式

像其它語(yǔ)言一樣,ruby也為a=a+2提供了類似a+=2的快捷方式。

第二種方式是第一種的深入,可以讓操作符當(dāng)成方法來(lái)工作。

class?Bowdlerize
??def?initialize(aString)
????@value?=?aString.gsub(/[aeiou]/,?'*')
??end
??def?+(other)
????Bowdlerize.new(self.to_s?+?other.to_s)
??end
??def?to_s
????@value
??end
end
a?=?Bowdlerize.new("damn?") ? d*mn
a?+=?"shame" ? d*mn?sh*m*

條件執(zhí)行(Conditional Execution)

Ruby有幾種不同的機(jī)制來(lái)實(shí)現(xiàn)條件執(zhí)行,大多數(shù)都感覺(jué)很類似,也有一些很靈巧,在深入討論之前,我們先來(lái)花點(diǎn)時(shí)間看看布爾表達(dá)式。

Boolean 表達(dá)式

Ruby中的true定義很簡(jiǎn)單,任何不是nil和false常量的東西都是true,你會(huì)發(fā)現(xiàn)系統(tǒng)的實(shí)現(xiàn)庫(kù)中很多這種用法。比如, IO#gets ,用來(lái)返回一個(gè)文件的下一行,如果到了文件末尾,返回nil,所以,我們才可以這樣通過(guò)while來(lái)循環(huán)讀取數(shù)據(jù):

while?line?=?gets
??#?process?line
end

但是,這里對(duì)于c和perl程序員來(lái)說(shuō)有一個(gè)誤區(qū),數(shù)字0和長(zhǎng)度為0的字符串都不會(huì)被解釋成false值,需要注意。

Defined?, And, Or, 和 Not

Ruby支持所有標(biāo)準(zhǔn)的布爾操作,另外,還引入了新的操作符defined?

操作符``and'' 和``&&'' 只有當(dāng)兩面的值都為真才會(huì)返回真,第一個(gè)值為真,才會(huì)判斷第二個(gè)值,否則直接返回假。這兩個(gè)操作符的區(qū)別是優(yōu)先級(jí)不同(and低于 &&)

類似的 ``or'' 和``||''有一方為真就會(huì)返回真,如果第一個(gè)為真,則不會(huì)判斷后面的值,類似and,這兩個(gè)操作符只有優(yōu)先級(jí)的不同。

and和or有相同的優(yōu)先級(jí),而&&的優(yōu)先級(jí)高于||。

?

``not'' and ``!'' 返回操作數(shù)的相反的值,如果操作數(shù)為true,則這個(gè)操作符返回false。并且and和!也只是優(yōu)先級(jí)不同。

所有的這些操作符和優(yōu)先級(jí)都在18章有詳細(xì)講述。

操作符defined?將返回nil,如果操作數(shù)沒(méi)有定義的話。否則,將返回后面參數(shù)的描述信息。

?

defined??1 ? "expression"
defined??dummy ? nil
defined??printf ? "method"
defined??String ? "constant"
defined??$& ? nil
defined??$_ ? "global-variable"
defined??Math::PI ? "constant"
defined??(?c,d?=?1,2?) ? "assignment"
defined??42.abs ? "method"

除了這些布爾表達(dá)式,Ruby對(duì)象還支持使用 ==, ===, <=>, =~, eql?, 和equal?進(jìn)行對(duì)象之間的比較。除了<=>之外這些操作符都在Object類中定義,但是經(jīng)常被子類重載。比如,類Array重定義了==方法,判斷兩個(gè)數(shù)組相同的條件事它們的個(gè)數(shù)相同,同一位置的元素也相同。

通用比較操作符
操作符 意義
== 測(cè)試是否相同
=== 在case中的when語(yǔ)句判斷是否相等
<=> 通用比較操作符,根據(jù)前面的對(duì)象小于,等于還是大于后面的對(duì)象,返回 -1, 0, 或者 +1。
<, <=, >=, > 小于,小于等于,大于等于,大于
=~ 正則表達(dá)式匹配
eql? 如果前后兩個(gè)對(duì)象都是同一類型,則返回true: 1 == 1.0返回true但是 1.eql?(1.0) 結(jié)果為false。
equal? 只有兩個(gè)對(duì)象有相同的object id 才返回true。

==和=~都有相反的操作符!=和!~,但是Ruby會(huì)將程序中的a!=b轉(zhuǎn)換為!(a==b),a!~b轉(zhuǎn)換成!(a=~b),如果你自己的類中重新寫了==和=~方法,那么你同時(shí)的到了!=和!~兩個(gè)方法;同時(shí),你也不能離開了==和=~而孤立的定義!=和!~兩個(gè)方法。

你可以使用Ruby? range 作為一個(gè)布爾表達(dá)式,一個(gè)類似 exp1..exp2 的range只有在遇到exp1為true,然后exp2又為true之后,才會(huì)返回true。下面循環(huán)部分有例子。

最后,你可以用正則表達(dá)式來(lái)當(dāng)作一個(gè)布爾表達(dá)式。Ruby expands it to $_=~/re/.

If 和 Unless表達(dá)式

Ruby中的if語(yǔ)句跟其他語(yǔ)言類似。

if?aSong.artist?==?"Gillespie"?then
??handle?=?"Dizzy"
elsif?aSong.artist?==?"Parker"?then
??handle?=?"Bird"
else
??handle?=?"unknown"
end

如果你的if語(yǔ)句寫在多行上,可以省略then關(guān)鍵字。

if?aSong.artist?==?"Gillespie"
??handle?=?"Dizzy"
elsif?aSong.artist?==?"Parker"
??handle?=?"Bird"
else
??handle?=?"unknown"
end

但是,如果你的語(yǔ)句都寫在一行上,then應(yīng)該寫上來(lái)分開布爾表達(dá)式和后面的語(yǔ)句。

if?aSong.artist?==?"Gillespie"?then??handle?=?"Dizzy"
elsif?aSong.artist?==?"Parker"?then??handle?=?"Bird"
else??handle?=?"unknown"
end

你可以使用0個(gè)或多個(gè)elsif語(yǔ)句,和一個(gè)可選的else語(yǔ)句。

就像我們前面說(shuō)道的,if是一個(gè)表達(dá)式,不是一個(gè)statement,它可以返回一個(gè)值,你不必使用if表達(dá)式的返回值,但是它可能有些用處。

handle?=?if?aSong.artist?==?"Gillespie"?then
???????????"Dizzy"
?????????elsif?aSong.artist?==?"Parker"?then
???????????"Bird"
?????????else
???????????"unknown"
?????????end

Ruby也未if提供了一個(gè)否定的形式,unless:

unless?aSong.duration?>?180?then
??cost?=?.25
else
??cost?=?.35
end

最后,也為使用C語(yǔ)言的程序員準(zhǔn)備了條件表達(dá)式:

cost?=?aSong.duration?>?180???.35?:?.25

這個(gè)條件表達(dá)式在根據(jù)?前面的布爾值為true或false返回冒號(hào)前面或后面的值。在這個(gè)例子中,如果歌曲的時(shí)長(zhǎng)大于3分鐘,將返回.35,否則返回.25,然后,將這個(gè)值賦給cost。

If 和 Unless 修飾符(Modifiers)

Ruby也借鑒了Perl的一些特點(diǎn),語(yǔ)句修飾符(Statement modifiers)使我們可以在語(yǔ)句末尾加上條件語(yǔ)句。

mon,?day,?year?=?$1,?$2,?$3?if?/(\d\d)-(\d\d)-(\d\d)/
puts?"a?=?#{a}"?if?fDebug
print?total?unless?total?==?0

對(duì)于if修飾符來(lái)說(shuō),只有當(dāng)if后面的條件為true,前面的語(yǔ)句才會(huì)執(zhí)行,unless正好和if相反。

while?gets
??next?if?/^#/????????????#?Skip?comments
??parseLine?unless?/^$/???#?Don't?parse?empty?lines
end

因?yàn)閕f本身也是表達(dá)式,所以下面的寫法將會(huì)使代碼變得難懂。

if?artist?==?"John?Coltrane"
??artist?=?"'Trane"
end?unless?nicknames?==?"no"

 

Case 表達(dá)式

Ruby的 case 表達(dá)式非常強(qiáng)大,就像多個(gè)if的固化物一樣。

case?inputLine



??when?"debug"          
????dumpDebugInfo          
????dumpSymbols


??when?/p\s+(\w+)/           
????dumpVariable($1)

??when?"quit",?"exit"           
????exit

??else           
????print?"Illegal?command:?#{inputLine}"           
end 

像if一樣,case返回最后執(zhí)行的語(yǔ)句的結(jié)果,如果你的when和后面的語(yǔ)句都在一行,你也需要加一個(gè)then關(guān)鍵字。

kind?=?case?year
?????????when?1850..1889?then?"Blues"
?????????when?1890..1909?then?"Ragtime"
?????????when?1910..1929?then?"New?Orleans?Jazz"
?????????when?1930..1939?then?"Swing"
?????????when?1940..1950?then?"Bebop"
?????????else?????????????????"Jazz"
???????end

case 操作符根據(jù)case后面目標(biāo)的值,跟每個(gè)when后面的值用===進(jìn)行判斷,

operates by comparing the target (the expression after the keyword case) with each of the comparison expressions after the when keywords. This test is done using comparison?===?target. As long as a class defines meaningful semantics for === (and all the built-in classes do), objects of that class can be used in case expressions.

For example, regular expressions define === as a simple pattern match.

case?line
??when?/title=(.*)/
????puts?"Title?is?#$1"
??when?/track=(.*)/
????puts?"Track?is?#$1"
??when?/artist=(.*)/
????puts?"Artist?is?#$1"
end

Ruby classes are instances of class Class, which defines === as a test to see if the argument is an instance of the class or one of its superclasses. So (abandoning the benefits of polymorphism and bringing the gods of refactoring down around your ears), you can test the class of objects:

case?shape
??when?Square,?Rectangle
????#?...
??when?Circle
????#?...
??when?Triangle
????#?...
??else
????#?...
end

循環(huán)

不要告訴他人,Ruby支持原始的靈巧的內(nèi)建循環(huán)結(jié)構(gòu)。

while循環(huán)根據(jù)它的條件的真假來(lái)執(zhí)行0次或者多次語(yǔ)句,比如,下面程序?qū)⒁恢边\(yùn)行,直到輸入被打斷。

while?gets
??#?...
end

util也可以用來(lái)循環(huán),知道條件為真,才停止操作。

until?playList.duration?>?60
??playList.add(songList.pop)
end

像if和unless一樣,while和until也可以用作語(yǔ)句操作符。

a?*=?2?while?a?<?100
a?-=?10?until?a?<?100

在前面的布爾表達(dá)式中,我們說(shuō)過(guò)range也可以作為布爾表達(dá)式,這個(gè)機(jī)制多用于循環(huán)中,在下面的例子中,我們從一個(gè)包含從first到tenth的數(shù)字的文本文件中讀取數(shù)據(jù),但是只打印從以third開頭的行,直到遇到fifth開頭的行為止。

file?=?File.open("ordinal")
while?file.gets
??print??if?/third/?..?/fifth/
end
打印結(jié)果:
third
fourth
fifth

The elements of a range used in a boolean expression can themselves be expressions. These are evaluated each time the overall boolean expression is evaluated. For example, the following code uses the fact that the variable $. contains the current input line number to display line numbers one through three and those between a match of /eig/ and /nin/.

file?=?File.open("ordinal")
while?file.gets
??print?if?($.?==?1)?||?/eig/?..?($.?==?3)?||?/nin/
end
produces:
first
second
third
eighth
ninth

這里有一點(diǎn)需要注意,當(dāng)while和until用作語(yǔ)句修飾符的時(shí)候,如果它們修飾的語(yǔ)句以begin開頭,end結(jié)尾,這段代碼將總會(huì)執(zhí)行,而不管后面的條件。

print?"Hello\n"?while?false
begin
??print?"Goodbye\n"
end?while?false
produces:
Goodbye

迭代Iterators

上面我們知道了,Ruby支持簡(jiǎn)單的循環(huán),比如,Ruby沒(méi)有for循環(huán),而c和JAV等都支持for循環(huán)的,但是Ruby提供了其他的機(jī)制,比如迭代,提供了類似的功能。

讓我們看看一個(gè)例子:

3.times?do
??print?"Ho!?"
end
produces:
Ho!?Ho!?Ho!

這可以避免off-by-1 錯(cuò)誤,這個(gè)循環(huán)將執(zhí)行3次。除了times,整數(shù)還可以接收一些方法來(lái)執(zhí)行循環(huán),比如downto,upto,和step等。比如,傳統(tǒng)的從0到9的循環(huán)(類似for( i=0; i < 10; i++)) 類似下面的樣子:

0.upto(9)?do?|x|
??print?x,?"?"
end
produces:
0?1?2?3?4?5?6?7?8?9

一個(gè)從0到12,步長(zhǎng)為3的循環(huán)如下:

0.step(12,?3)?{|x|?print?x,?"?"?}
produces:
0?3?6?9?12

用于數(shù)組和其它容器的迭代的each方法也可以用來(lái)循環(huán)。

[?1,?1,?2,?3,?5?].each?{|val|?print?val,?"?"?}
produces:
1?1?2?3?5

如果一個(gè)類支持了each方法,那么在模塊Enumerable 中的方法也可以直接使用。比如,F(xiàn)ile類提供了each方法,依次返回一個(gè)文件的每一行。使用Enumerable中的grep方法,我們可以只迭代符合條件的行。

File.open("ordinal").grep?/d$/?do?|line|
??print?line
end
produces:
second
third

最后也是最簡(jiǎn)單的,Ruby提供了一個(gè)內(nèi)建的最基本的迭代器loop。

loop?{
??#?block?...
}

loop迭代器一直調(diào)用給定的block(或者你調(diào)用了break跳出循環(huán),后面會(huì)講到)。

For ... In

前面我們說(shuō)道Ruby支持的最基本循環(huán)視while和until,而for指的什么呢,可以看如下代碼:

for?aSong?in?songList
??aSong.play
end

Ruby將會(huì)把它翻譯為如下:

songList.each?do?|aSong|
??aSong.play
end

for和each的唯一區(qū)別是局部變量的作用域。

你可以在支持each的類上使用for方法,比如Array或者Range。

for?i?in?['fee',?'fi',?'fo',?'fum']
??print?i,?"?"
end
for?i?in?1..3
??print?i,?"?"
end
for?i?in?File.open("ordinal").find_all?{?|l|?l?=~?/d$/}
??print?i.chomp,?"?"
end
produces:
fee?fi?fo?fum?1?2?3?second?third

一旦你的類支持了each方法,你就可以使用for來(lái)進(jìn)行遍歷。

class?Periods
??def?each
????yield?"Classical"
????yield?"Jazz"
????yield?"Rock"
??end
end
 
periods?=?Periods.new             
for?genre?in?periods             
??print?genre,?"?"             
end
 
produces:
Classical?Jazz?Rock

Break, Redo, 和 Next

循環(huán)控制結(jié)構(gòu) break, redo, 和 next 讓你可以控制循環(huán)或者迭代器的流程。

break 立即結(jié)束當(dāng)前循環(huán),然后跳出去執(zhí)行循環(huán)后面的語(yǔ)句。redo從這次循環(huán)體的頭開始重新執(zhí)行,但是不會(huì)在對(duì)條件進(jìn)行運(yùn)算或者從迭代中取下一個(gè)值。next跳到本次循環(huán)末尾,開始執(zhí)行下一次循環(huán)。

while?gets
??next?if?/^\s*#/???#?skip?comments
??break?if?/^END/???#?stop?at?end
????????????????????#?substitute?stuff?in?backticks?and?try?again
??redo?if?gsub!(/`(.*?)`/)?{?eval($1)?}
??#?process?line?...
end

這些關(guān)鍵字也可以用在基于迭代器的循環(huán)機(jī)制中。

i=0
loop?do
??i?+=?1
??next?if?i?<?3
??print?i
??break?if?i?>?4
end
produces:
345

Retry

redo使一個(gè)循環(huán)從當(dāng)前迭代中重新執(zhí)行。有時(shí)候,你需要從新開始一個(gè)循環(huán),retry從新開始任何地迭代循環(huán)。

for?i?in?1..100
??print?"Now?at?#{i}.?Restart??"
??retry?if?gets?=~?/^y/i
end

運(yùn)行上面的程序,結(jié)果如下:

Now?at?1.?Restart??n
Now?at?2.?Restart??y
Now?at?1.?Restart??n
?.?.?.

retry 將重新計(jì)算條件值,然后再開始循環(huán)。Ruby文檔有如下例子:

def?doUntil(cond)
??yield
??retry?unless?cond
end

 
i?=?0              
doUntil(i?>?3)?{              
??print?i,?"?"              
??i?+=?1              
}
produces:
0?1?2?3?4

變量作用域和循環(huán)

while,until和for循環(huán)內(nèi)建于Ruby語(yǔ)言之中,沒(méi)有引入新的作用域,前面定義的局部變量可以在循環(huán)中使用,在循環(huán)中創(chuàng)建的變量在后面的代碼也可以使用。

而對(duì)loop或each使用block來(lái)說(shuō)則不一樣了。在這個(gè)block中創(chuàng)建的變量在外面是不能訪問(wèn)的。

[?1,?2,?3?].each?do?|x|
??y?=?x?+?1
end
[?x,?y?]
produces:
prog.rb:4: undefined local variable or method `x'
for #<Object:0x401c2ce0> (NameError)

然而,如果block中的變量和前面已經(jīng)定義的變量重名的話,已經(jīng)存在的變量將會(huì)在塊中使用,而在塊執(zhí)行完成后,這個(gè)變量的值也會(huì)改變。下面的例子,我們看到block執(zhí)行之后,兩個(gè)變量都改變了。

x?=?nil
y?=?nil
[?1,?2,?3?].each?do?|x|
??y?=?x?+?1
end
[?x,?y?] ? [3,?4]


Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Copyright ? 2001 by Addison Wesley Longman, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/)).

Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.

Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.
?? ??: ?? ??: