Ruby.new
當(dāng)我們開(kāi)始要寫(xiě)這本書(shū)的時(shí)候,有一個(gè)偉大重要的計(jì)劃,因?yàn)槲覀兡菚r(shí)候還很年輕。我們決定從最高到低層次來(lái)記錄ruby語(yǔ)言,從類(lèi)和對(duì)象開(kāi)始,然后以詳細(xì)的核心語(yǔ)法結(jié)束。那時(shí)候,這看來(lái)是個(gè)不錯(cuò)的選擇,幾乎Ruby中很多東西都是對(duì)象,感覺(jué)也也應(yīng)該先說(shuō)說(shuō)對(duì)象。
我們是這么想的。
但是,那樣來(lái)描述一門(mén)語(yǔ)言顯得比較困難:如果我們不曾涉及到string,if語(yǔ)句,賦值語(yǔ)句,或其他詳細(xì)的東西,很難寫(xiě)一個(gè)類(lèi)的例子。貫穿于我們從高到低的計(jì)劃,我們不得不穿插一些低層次的細(xì)節(jié)來(lái)使得例子能被讀者看懂。
所以,我們開(kāi)始了另一個(gè)計(jì)劃,雖然我們?nèi)匀粡膶?duì)象開(kāi)始,但是在這之前,先用一章來(lái)描述ruby比較普通的特點(diǎn),這都會(huì)在將來(lái)的例子里出現(xiàn)。就讓我們從一小段指南開(kāi)始,然后再進(jìn)入剩余的部分。
Ruby 是面向?qū)ο蟮恼Z(yǔ)言
重申一遍的是,ruby是純的面向?qū)ο蟮恼Z(yǔ)言,你操作的一切都是對(duì)象,并且他們產(chǎn)生的結(jié)果也是對(duì)象。盡管很多其他語(yǔ)言也說(shuō)自己是面向?qū)ο蟮?,但是他們總是用不同的解釋?lái)闡述什么是面向?qū)ο?,用不同的術(shù)語(yǔ)描述他們的使用的觀念。
所以,在進(jìn)一步深入到詳細(xì)內(nèi)容之前,先來(lái)簡(jiǎn)要看看我們要用到的術(shù)語(yǔ)和符號(hào)。
當(dāng)你編寫(xiě)面向?qū)ο蟮拇a時(shí),總會(huì)將現(xiàn)實(shí)世界中的事物模型化到你的代碼之中,在建模的過(guò)程中,你會(huì)發(fā)現(xiàn)事物能分成不同的對(duì)象(類(lèi))在代碼中實(shí)現(xiàn),比如在自動(dòng)點(diǎn)唱機(jī)(jukebox)中,歌曲就是這樣的例子。在ruby里,我們用class來(lái)表示一個(gè)對(duì)象類(lèi)。一個(gè)類(lèi)是狀態(tài)(比如歌曲名稱等)和方法(比如播放,停止)等地組合。
當(dāng)你寫(xiě)完了類(lèi),就可以為每個(gè)類(lèi)建立若干個(gè)實(shí)例,比如對(duì)于jukebox來(lái)說(shuō),它包含一個(gè)類(lèi)song,我們可以建立諸如``Ruby Tuesday,'' ``Enveloped in Python,'' ``String of Pearls,'' ``Small talk,''等實(shí)例。對(duì)象這個(gè)詞經(jīng)常和類(lèi)的實(shí)例交換使用,一般的時(shí)候我們還是樂(lè)意叫它對(duì)象。
在 Ruby中,要建立這些對(duì)象,可以調(diào)用類(lèi)的構(gòu)造函數(shù)。這個(gè)函數(shù)是類(lèi)中的特殊的函數(shù)標(biāo)準(zhǔn)名稱是new
.
song1?=?Song.new("Ruby?Tuesday")
song2?=?Song.new("Enveloped?in?Python")
#?and?so?on
|
這兩個(gè)實(shí)例都來(lái)源于一個(gè)類(lèi),但他們有不同的特征。首先,每個(gè)對(duì)象都有一個(gè)唯一的對(duì)象標(biāo)識(shí)符(object identifier)也就是對(duì)象id。第二,你可以定義實(shí)例變量,每個(gè)實(shí)例的實(shí)例變量都是不同的。實(shí)例變量保存著實(shí)例的不同狀態(tài)。上面的例子中,兩個(gè)實(shí)例是不同的因?yàn)樗麄冇兄煌母枨Q。
在每一個(gè)類(lèi)里面,還可以定義實(shí)例方法(instance methods),每個(gè)方法都是都是一塊代碼的集合,根據(jù)訪問(wèn)限制的不同,可以在內(nèi)部或者外部訪問(wèn)這些方法。這些方法可以訪問(wèn)對(duì)象的實(shí)例變量,也就是對(duì)象的狀態(tài)。
要想調(diào)用一個(gè)方法,可以向這個(gè)對(duì)象發(fā)送一個(gè)消息。這個(gè)消息包括方法名和一些參數(shù)。[
這種用發(fā)消息的方式調(diào)用方法來(lái)自smalltalk]。當(dāng)一個(gè)對(duì)象收到消息,它會(huì)檢查自己所屬的類(lèi)是否有對(duì)應(yīng)的方法,如果有,那么就執(zhí)行這個(gè)方法,如果沒(méi)有,下面會(huì)講到該會(huì)如何。
方法和消息的關(guān)系聽(tīng)起來(lái)可能有些復(fù)雜,但是實(shí)際上這樣很自然。我們先來(lái)看看一些方法調(diào)用(記住}}在這里表示的是對(duì)應(yīng)的表達(dá)式返回的結(jié)果):
"gin?joint".length |
}} |
9 |
"Rick".index("c") |
}} |
2 |
-1942.abs |
}} |
1942 |
sam.play(aSong) |
}} |
"duh?dum,?da?dum?de?dum?..." |
上面的例子中,點(diǎn)(.)前面的是消息的接收者,點(diǎn)后面的是要調(diào)用的方法名。第一個(gè)例子中,調(diào)用一個(gè)字符串的方法,得到它的長(zhǎng)度,第二個(gè)得到一個(gè)字符在字符串中的位置,第三個(gè)取得了一個(gè)數(shù)的絕對(duì)值,第四個(gè)調(diào)用sam對(duì)象的play方法。
It's worth noting here a major difference between Ruby and most other languages. 在java里,要想得到一個(gè)數(shù)的絕對(duì)值,要調(diào)用額外的方法,并且把那個(gè)數(shù)字傳過(guò)去,比如這樣:
number?=?Math.abs(number)?????//?Java?code
|
在Ruby中, 得到一個(gè)數(shù)的絕對(duì)值的功能在數(shù)字對(duì)象里是內(nèi)建的,所有細(xì)節(jié)都在內(nèi)部,我們只需要調(diào)用就行了。
同樣,對(duì)其他ruby中的對(duì)象來(lái)說(shuō)也是這樣的。比如在c語(yǔ)言中要寫(xiě)
strlen(name)
,在ruby中,只要
name.length
就行了。這也是為什么我們說(shuō)ruby是一個(gè)純的oo語(yǔ)言。
Ruby基礎(chǔ)
一個(gè)人在學(xué)習(xí)一門(mén)新的語(yǔ)言的時(shí)候,都不大愿意去看長(zhǎng)篇大論的繁瑣的語(yǔ)法,所以,這一節(jié)我們打算涉及到一些顯著的特點(diǎn),如果你打算寫(xiě)ruby程序的話,這些東西你都應(yīng)該知道。在第18章,我們將會(huì)更深入的解釋類(lèi)和對(duì)象。
讓我們從一個(gè)簡(jiǎn)單的程序開(kāi)始。這里有一個(gè)方法,它返回一個(gè)string類(lèi)型的值,簡(jiǎn)單的把一個(gè)字符串加到用戶名后面。然后調(diào)用這個(gè)函數(shù)2次。
def?sayGoodnight(name)
??result?=?"Goodnight,?"?+?name
??return?result
end
#?Time?for?bed...
puts?sayGoodnight("John-Boy")
puts?sayGoodnight("Mary-Ellen")
|
首先,從大體上我們看到,ruby的語(yǔ)法還是比較簡(jiǎn)單的,首先,你不必每行都寫(xiě)個(gè)分號(hào),Ruby注釋以#開(kāi)頭,直到行尾。 Code layout is pretty much up to you; indentation is not significant.
Methods定義以關(guān)鍵字def開(kāi)始,接著是方法名(這里是sayGoodnight)和用兩個(gè)小括號(hào)括起來(lái)的方法參數(shù),ruby不需要用{ }來(lái)界定程序主體,只需要關(guān)鍵字end就行了。這個(gè)程序也相當(dāng)簡(jiǎn)單,第一行把``Goodnight, ''加上參數(shù)name,并把它賦給了局部變量result,第二行把結(jié)果返回給調(diào)用者。注意我們不需要定義變量result,當(dāng)給它賦值的時(shí)候,系統(tǒng)會(huì)自動(dòng)創(chuàng)建的。
最后我們調(diào)用了2次這個(gè)方法,并把結(jié)果傳給puts函數(shù),這個(gè)函數(shù)簡(jiǎn)單的再新行上打印傳給它的參數(shù)而已,最后結(jié)果像這樣:
Goodnight,?John-Boy
Goodnight,?Mary-Ellen
|
其實(shí) ``puts sayGoodnight("John-Boy")'' 包括了2個(gè)函數(shù)調(diào)用,一個(gè)調(diào)用
sayGoodnight
,另一個(gè)調(diào)用
puts
,但是為什么puts調(diào)用沒(méi)有用括號(hào)呢?實(shí)際上,下面的調(diào)用都是等價(jià)的:
puts?sayGoodnight?"John-Boy"
puts?sayGoodnight("John-Boy")
puts(sayGoodnight?"John-Boy")
puts(sayGoodnight("John-Boy"))
|
但是事實(shí)上,這樣很難看清楚哪個(gè)參數(shù)是給哪個(gè)方法的,所以還是建議在方法后面加上括號(hào),除非是非常簡(jiǎn)單的場(chǎng)合。
這個(gè)方法還展示了string對(duì)象,有很多種辦法可以創(chuàng)建string對(duì)象,但最普通的要算用string literals了:?jiǎn)我?hào)或雙引號(hào)包起來(lái)的一組字符。它們的區(qū)別是ruby構(gòu)建這兩種字符串時(shí)要做的操作。對(duì)單引號(hào)引起來(lái)的字符串來(lái)說(shuō),ruby做的工作會(huì)很少,單引號(hào)引起來(lái)得部分就是它的值。如果是雙引號(hào)引起來(lái)得,則要做多一些工作了。首先,它檢查是否包含反斜線,也就是轉(zhuǎn)義符,然后用適當(dāng)?shù)亩M(jìn)制值代替,最常見(jiàn)的就是"\n"了,它將會(huì)被換行替換。
比如:
puts?"And?Goodnight,\nGrandma"
|
?
產(chǎn)生結(jié)果如下:
?
處理雙引號(hào)括起來(lái)的字符串的時(shí)候如果做的第二件事情就是表達(dá)式處理(expression interpolation)。#{ expression }將被expression的值代替,例如,下面的方法和剛才的例子是一樣的結(jié)果:
def?sayGoodnight(name)
??result?=?"Goodnight,?#{name}"
??return?result
end
|
當(dāng)ruby構(gòu)造這個(gè)字符串時(shí),先檢查name的值,然后用這個(gè)值替換到字符串里面去。表達(dá)式要放到
#{...}
結(jié)構(gòu)里面去。As a shortcut, you don't need to supply the braces when the expression is simply a global, instance, or class variable. For more information on strings, as well as on the other Ruby standard types, see Chapter 5, which begins on page 47.
最后,我們還可以把剛才的函數(shù)簡(jiǎn)化成這樣的。一個(gè)ruby函數(shù)返回的結(jié)果就是最后一行的值,所以這個(gè)函數(shù)也可以寫(xiě)成如下:
def?sayGoodnight(name)
?? "Goodnight,?#{name}"
end
|
We promised that this section would be brief. We've got just one more topic to cover: Ruby names. For brevity, we'll be using some terms (such as class variable) that we aren't going to define here. However, by talking about the rules now, you'll be ahead of the game when we actually come to discuss instance variables and the like later.
Ruby uses a convention to help it distinguish the usage of a name: the first characters of a name indicate how the name is used. Local variables, method parameters, and method names should all start with a lowercase letter or with an underscore. Global variables are prefixed with a dollar sign ($), while instance variables begin with an ``at'' sign (@). Class variables start with two ``at'' signs (@@). Finally, class names, module names, and constants should start with an uppercase letter. Samples of different names are given in Table 2.1 on page 10.
Following this initial character, a name can be any combination of letters, digits, and underscores (with the proviso that the character following an @ sign may not be a digit).
Example variable and class names
Variables |
Constants and |
Local |
Global |
Instance |
Class |
Class Names |
name |
$debug |
@name |
@@total |
PI |
fishAndChips |
$CUSTOMER |
@point_1 |
@@symtab |
FeetPerMile |
x_axis |
$_ |
@X |
@@N |
String |
thx1138 |
$plan9 |
@_ |
@@x_pos |
MyClass |
_26 |
$Global |
@plan9 |
@@SINGLE |
Jazz_Song |
 |
|
數(shù)組和哈希表
ruby的數(shù)組和哈希是有索引的集合,它們存放著各種對(duì)象,并且用一個(gè)key來(lái)訪問(wèn)。對(duì)數(shù)組來(lái)說(shuō)這個(gè)key是一個(gè)整數(shù),而哈希則支持任何對(duì)象作為key。兩者都可以動(dòng)態(tài)增長(zhǎng),如果他們需要的話。訪問(wèn)數(shù)組是一件很方便的事情,但是訪問(wèn)哈希就要復(fù)雜一些了。
最簡(jiǎn)單的創(chuàng)建和初始化一個(gè)數(shù)組的方法是用一對(duì)中括號(hào)包含一組值,這組值用逗號(hào)分割。然后用一個(gè)索引可以訪問(wèn)單獨(dú)的任何一個(gè)元素。如下:
a?=?[?1,?'cat',?3.14?]???#?array?with?three?elements |
#?access?the?first?element |
a[0] |
}} |
1 |
#?set?the?third?element |
a[2]?=?nil |
#?dump?out?the?array |
a |
}} |
[1,?"cat",?nil] |
也可以這樣創(chuàng)建新的空的數(shù)組:用空元素構(gòu)造或者調(diào)用Array的構(gòu)造函數(shù)
Array.new
.
empty1?=?[]
empty2?=?Array.new
|
當(dāng)然,像第一種方法那樣寫(xiě)很多引號(hào)和逗號(hào)可能很麻煩,但是ruby提供了一個(gè)好東西,如下面那樣%w可真管用:
a?=?%w{?ant?bee?cat?dog?elk?} |
a[0] |
}} |
"ant" |
a[3] |
}}
|
|
"dog" |
哈希和數(shù)組類(lèi)似,不過(guò)它不用[]來(lái)包括,而是用{},哈希里的每條記錄要兩個(gè)要素來(lái)表示,一個(gè)是關(guān)鍵字,另一個(gè)是對(duì)應(yīng)這個(gè)key的值。如:
instSection?=?{
??'cello'?????=>?'string',
??'clarinet'??=>?'woodwind',
??'drum'??????=>?'percussion',
??'oboe'??????=>?'woodwind',
??'trumpet'???=>?'brass',
??'violin'????=>?'string'
}
|
哈希的引用也是用[],像數(shù)組一樣,但是它的[]里面是key,可以是字符串不像數(shù)組,只能是整數(shù)比如:
instSection['oboe'] |
}} |
"woodwind" |
instSection['cello'] |
}} |
"string" |
instSection['bassoon'] |
}} |
nil |
從上面最后一個(gè)例子看出,如果哈希里不包含一個(gè)key值,則默認(rèn)會(huì)返回nil,這也是一個(gè)關(guān)鍵字(保留字),在條件運(yùn)算中,nil跟false是一樣的。如果你想改變這個(gè)默認(rèn)值,則可以在創(chuàng)建一個(gè)哈希的時(shí)候提供這個(gè)默認(rèn)值就行了,如下面的
?Hash.new(0)
中,0就是默認(rèn)值:
histogram?=?Hash.new(0) |
histogram['key1'] |
}} |
0 |
histogram['key1']?=?histogram['key1']?+?1 |
histogram['key1'] |
}} |
1 |
數(shù)組和哈希又很多其他有用的用法,可以參看書(shū)末附錄中的參考手冊(cè)。
條件控制
Ruby包括通常的一些條件控制語(yǔ)句,比如if,then,while等。 Java, C, 和 Perl 程序員可能會(huì)被打括號(hào){}弄得很煩亂,與此不同Ruby用關(guān)鍵字end來(lái)結(jié)束一塊代碼 ,比如:
if?count?>?10
??puts?"Try?again"
elsif?tries?==?3
??puts?"You?lose"
else
??puts?"Enter?a?number"
end
|
同樣,while語(yǔ)句看起來(lái)都是這樣的。
while?weight?<?100?and?numPallets?<=?30
??pallet?=?nextPallet()
??weight?+=?pallet.weight
??numPallets?+=?1
end
|
statement modifiers 是ruby語(yǔ)法中的一點(diǎn)特別之處,如果你的if或while條件下的語(yǔ)句特別簡(jiǎn)單,可以把他們寫(xiě)在一行上:先寫(xiě)表達(dá)式,然后跟著寫(xiě)if或者while語(yǔ)句,比如下面的例子:
if?radiation?>?3000
??puts?"Danger,?Will?Robinson"
end
|
可以改寫(xiě)成如下:
puts?"Danger,?Will?Robinson"?if?radiation?>?3000
|
同樣,
while循環(huán)如下:
while?square?<?1000
???square?=?square*square
end
|
更簡(jiǎn)潔的形式:
square?=?square*square??while?square?<?1000
|
statement modifiers對(duì)perl程序員來(lái)說(shuō)應(yīng)該比較熟悉。
正則表達(dá)式Regular Expressions
大多數(shù)語(yǔ)言都有字符串,整型,浮點(diǎn)型,數(shù)組等數(shù)據(jù)類(lèi)型,所以ruby中的大多數(shù)內(nèi)建類(lèi)型對(duì)大家來(lái)說(shuō)一定不算陌生。所謂的腳本語(yǔ)言比如perl,python,awk中都支持正則表達(dá)式,
However, until Ruby came along, regular expression support was generally built into only the so-called scripting languages, such as Perl, Python, and awk. This is a shame: regular expressions, although cryptic, are a powerful tool for working with text.
本書(shū)整個(gè)都包括正則表達(dá)式的內(nèi)容,所以這里沒(méi)必要用一節(jié)涵蓋所有內(nèi)容。所以,我們只會(huì)涉及到幾個(gè)正則表達(dá)式的例子。
正則表達(dá)式就是在一個(gè)字符串中查找一個(gè)匹配的模式,在Ruby中,要建立一個(gè)正在表達(dá)式,只要把要匹配的模式放到兩個(gè)斜線中就行了(/
pattern/),而且,在Ruby中,正則表達(dá)式也是對(duì)象,可以像對(duì)象一樣被操作。
例如,你寫(xiě)了一個(gè)模式,匹配一個(gè)字符串中的Perl或者Python,模式如下:
The forward slashes delimit the pattern, which consists of the two things we're matching, separated by a pipe character (``
|
''). You can use parentheses within patterns, just as you can in arithmetic expressions, so you could also have written this pattern as
在模式里,還可以指定重復(fù)的字符,比如
/ab+c/
匹配一個(gè)字符串包括一個(gè)a,一個(gè)或多個(gè)b,然后跟一個(gè)c。把加號(hào)改成星號(hào),即
/ab*c/
將匹配一個(gè)a,0個(gè)或多個(gè)b,然后是一個(gè)c。
在一個(gè)模式中,也可以匹配一類(lèi)字符,比如"\s"匹配一個(gè)空格,"\d"匹配數(shù)字,"\w"匹配在典型單詞出現(xiàn)的字符,"."匹配任何字符。
我們可以把這些規(guī)則寫(xiě)道一塊,生成一些比較有用的表達(dá)式。
/\d\d:\d\d:\d\d/?????#?a?time?such?as?12:34:56
/Perl.*Python/???????#?Perl,?zero?or?more?other?chars,?then?Python
/Perl\s+Python/??????#?Perl,?one?or?more?spaces,?then?Python
/Ruby?(Perl|Python)/?#?Ruby,?a?space,?and?either?Perl?or?Python
|
創(chuàng)建了一個(gè)模式,當(dāng)然要使用它。匹配操作符"=~
"可以用來(lái)在一個(gè)字符串中匹配一個(gè)模式,如果在字符串中找到匹配的模式,=~
返回它的開(kāi)始位置,否則返回nil。所以,你也可以將正則表達(dá)式放到if或者while語(yǔ)句中作為判斷條件。 比如,下面代碼判斷到如果一個(gè)字符串包括指定的模式(包含Perl或者Python),則輸出一條消息。
if?line?=~?/Perl|Python/
??puts?"Scripting?language?mentioned:?#{line}"
end
|
一個(gè)字符串中被匹配到的部分也可以用ruby自帶的替換函數(shù)替換成不同的值。
line.sub(/Perl/,?'Ruby')????#?replace?first?'Perl'?with?'Ruby'
line.gsub(/Python/,?'Ruby')?#?replace?every?'Python'?with?'Ruby'
|
在本書(shū)以后 章節(jié)中,還有很多關(guān)于正則表達(dá)式的東西要講述。
塊和迭代
這節(jié)簡(jiǎn)要介紹ruby特別的一點(diǎn)長(zhǎng)處。 一大塊代碼,可以像方法一樣被調(diào)用,好像是方法的參數(shù)一樣。你可以用塊來(lái)實(shí)現(xiàn)方法回調(diào)(比java的內(nèi)類(lèi)要簡(jiǎn)單多了),給一段代碼傳遞另一段代碼(比c的方法指針要靈活),并且可以實(shí)現(xiàn)迭代。塊用{}或者do…end包含起來(lái):
{?puts?"Hello"?}???????#?this?is?a?block
do?????????????????????#
??club.enroll(person)??#?and?so?is?this
??person.socialize?????#
end????????????????????#
|
當(dāng)你完成了一個(gè)塊,下一步可以用一個(gè)方法來(lái)調(diào)用這個(gè)塊,這個(gè)方法可以用yield關(guān)鍵字來(lái)調(diào)用一次或者多次塊。如下面這個(gè)例子,我們定義了一個(gè)方法,調(diào)用了兩次yield,然后調(diào)用這個(gè)方法,并且在同一行放了一個(gè)塊:
def?callBlock
??yield
??yield
end
callBlock?{?puts?"In?the?block"?}
|
結(jié)果如下:
In?the?block
In?the?block
|
可以看到代買(mǎi)(puts "In the block"
)執(zhí)行了兩次,每次yield調(diào)用都會(huì)執(zhí)行一次。
而且,我們還可以給yield傳參數(shù),這個(gè)參數(shù)也會(huì)被傳到塊中。在塊中,列出參數(shù)的名字,用豎線 "|" 格開(kāi)
def callBlock
yield ,
end
callBlock { |, | ... }
|
塊代碼貫穿于Ruby庫(kù)中迭代的實(shí)現(xiàn)之中:某種集合返回下一個(gè)值得方法,比如數(shù)組
a?=?%w(?ant?bee?cat?dog?elk?)????#?create?an?array
a.each?{?|animal|?puts?animal?}??#?iterate?over?the?contents
|
產(chǎn)生:
讓我們看看上面的例子是如何來(lái)實(shí)現(xiàn)數(shù)組的
each
迭代的,each迭代循環(huán)整個(gè)數(shù)組,從第一個(gè)到最后一個(gè)元素,對(duì)每一個(gè)元素,調(diào)用yield。偽代碼表示如下:
#?within?class?Array...
def?each
??for?each?element
????yield(element)
??end
end
|
你可以循環(huán)迭代數(shù)組中的每個(gè)元素,并且提供一個(gè)塊來(lái)處理。
[?'cat',?'dog',?'horse'?].each?do?|animal|
??print?animal,?"?--?"
end
|
結(jié)果:
ruby也提供了類(lèi)似c和java的其他一些循環(huán)結(jié)構(gòu),而且非常容易使用,每個(gè)方法可以運(yùn)行0次和多次提供的塊代碼。
5.times?{??print?"*"?}
3.upto(6)?{|i|??print?i?}
('a'..'e').each?{|char|?print?char?}
|
產(chǎn)生:
這里,我們讓數(shù)字5調(diào)用塊5次,然后從3到6調(diào)用另一個(gè)塊,每次給塊傳遞下一個(gè)循環(huán)值,最后,在從a到e的范圍里用each方法循環(huán)。
讀寫(xiě)操作
Ruby自帶了豐富的I/O操作庫(kù),在本書(shū)的例子中,我們只會(huì)用到很少的一些方法。目前我們已經(jīng)接觸到了2個(gè)輸出方法,puts和print。puts依次輸出所有的參數(shù),每個(gè)參數(shù)之后都會(huì)加一個(gè)換行;print也類(lèi)似, 不過(guò)不會(huì)在每個(gè)參數(shù)后面加入新行,比如(譯者測(cè)試的例子,原書(shū)無(wú)):
irb(main):011:0> puts "puts 1","puts 2" puts 1 puts 2 => nil irb(main):012:0> printf " puts %s puts %s",1,2 puts 1 puts 2=> nil #nil出現(xiàn)在此處 irb(main):013:0> |
這兩個(gè)方法都可以輸出到I/O對(duì)象,默認(rèn)都輸出到控制臺(tái)。另一個(gè)經(jīng)常用到的是printf,類(lèi)似c里的,是格式化輸出語(yǔ)句:
printf?"Number:?%5.2f,?String:?%s",?1.23,?"hello"
|
produces:
Number:??1.23,?String:?hello
|
printf的格式如下:pringf(格式控制,輸出列表)這個(gè)例子里,格式化字符串"Number: %5.2f, String: %s"
中有兩個(gè)參數(shù),第一個(gè)是一個(gè)浮點(diǎn)型(%5.2f),5表示一共有5個(gè)數(shù)字,2表示小數(shù)點(diǎn)后邊有兩位;第二個(gè)表示是一個(gè)字符串。
讀入輸入字符有幾種方法,按傳統(tǒng)慣例來(lái)說(shuō)最簡(jiǎn)單的是用gets。它返回你的程序標(biāo)準(zhǔn)輸入的下一行。(下例為譯者修改過(guò)的)
irb(main):016:0> line=gets ruby => "ruby\n" irb(main):017:0> puts line ruby => nil irb(main):018:0> |
不過(guò)gets也有一個(gè)副作用
:用它得到一行的時(shí)候,它還會(huì)將這個(gè)值存到一個(gè)全局變量$_里,這個(gè)變量很特殊,在很多場(chǎng)合,他都會(huì)作為一些方法的默認(rèn)值。比如你光運(yùn)行print而不帶任何參數(shù),就會(huì)輸出$_的值,如果你的if或者while沒(méi)有條件語(yǔ)句,而只有表達(dá)式,它們也會(huì)判斷當(dāng)前$_值的真假來(lái)做判斷。這些縮寫(xiě)可能會(huì)使你能夠?qū)懗龊芎?jiǎn)練的程序。比如下面的程序從輸入流接收數(shù)據(jù),打印出所有包含"Ruby"的行。
while?gets???????????#?assigns?line?to?$_
??if?/Ruby/??????????#?matches?against?$_
????print????????????#?prints?$_
??end
end
#以下代碼為譯者添加
irb(main):004:0> line=gets hehe # 此時(shí)$_=line="hehe" => "hehe\n" irb(main):006:0> print # print $_ hehe => nil irb(main):007:0> puts # 無(wú)效
=> nil irb(main):008:0> gets # 存到$_ xixi => "xixi\n" irb(main):009:0> print # print $_ xixi => nil irb(main):010:0>
|
Ruby特色的寫(xiě)法應(yīng)該用一個(gè)迭代如下:
ARGF.each?{?|line|??print?line??if?line?=~?/Ruby/?}
|
這里用到了一個(gè)預(yù)先定義好的對(duì)象ARGF,它代表了一個(gè)可以被程序使用的輸入流。
Onward and Upward
到這里,我們快速的瀏覽了ruby的一些基本特點(diǎn),我們知道了對(duì)象,方法字符串,容器,正則表達(dá)式,一些簡(jiǎn)單的條件控制,迭代等。希望這一章能幫助你很好的掌握本書(shū)的其他章節(jié)。
Time to move on, and up---up to a higher level. Next, we'll be looking at classes and objects, things that are at the same time both the highest-level constructs in Ruby and the essential underpinnings of the entire language.
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.