Ruby 基礎(chǔ)
作者:Ralf Wirdemann, Thomas Baustert
www.b-simple.de
2006.2.14
1.1 在線文檔和書籍
??? 語言資料上,如果要找核心和標(biāo)準(zhǔn)API的文檔可以去 www.ruby-lang.org,深步進(jìn)階我們推薦下面的書籍:
Dave Thomas: Programming Ruby, Second Edition, Pragmatic Bookshelf, 2005
Ruby書籍中的標(biāo)準(zhǔn)著作,極具推薦價(jià)值。
Hal Fulton: The Ruby Way, Sams, 2001
這部書不僅僅有Ruby語言的最新狀況,還提供了一百個(gè)案例,很有意思。
1.2 引言
??? Ruby 是一個(gè)純粹的面向?qū)ο蟮膭?dòng)態(tài)型語言。Ruby 程序不是被編譯成二進(jìn)制格式(如Java),而是直接由一個(gè)解釋器來處理。這門語言在1995年由松本行弘(Matsumoto Yukihiro)發(fā)布,除了 Smalltalk、Python 等語言以外,Perl 對它的影響是首當(dāng)其沖的。
??? Ruby 里的一切都是對象,它沒有原始類型(如Java)。除了面對對象,Ruby還提供了垃圾回收、異常、正則表達(dá)式,為迭代器和方法作參數(shù)的“代碼塊”,運(yùn)行期的類擴(kuò)展,線程及更多的東西。Ruby 語言易懂易用,原因在于它簡單、語法干凈。
1.3 Ruby 程序
??? Ruby 程序保存在以 .rb 結(jié)尾的文件里。程序內(nèi)容包含類、模塊、或者只是簡單的Ruby代碼。下面是地球人都知道的 Hello World 程序:
# hello.rb????????????????????????
puts "Hello World!"???????????????
??? 如果這個(gè)代碼是以 hello.rb 的文件名保存的,那么可以這樣調(diào)用:
> ruby hello.rb???????????????????
> Hello World!????????????????????
??? 在Windows下允許您以文件關(guān)聯(lián)的方式在IE中執(zhí)行;在 Linux/Unix 下您可按照自已的操作系統(tǒng)情況使用 Shebang行:
#!/usr/local/bin/ruby?????????????
puts "Hello World!"???????????????
??????????????????????????????????
#!/usr/bin/env ruby???????????????
puts "Hello World!"???????????????
??? 隨后直接執(zhí)行這個(gè)程序:
> chmod 744 hello.rb??????????????
> ./hello.rb??????????????????????
??? Ruby 的語句可以以分號(hào)結(jié)尾,但不是必須。 Ruby 是一個(gè)面向行的語言,也就是說,一個(gè)語句不需要以分號(hào)結(jié)尾,解釋器能夠明白下一行是進(jìn)一步的語句。下面前幾個(gè)語句的輸出相同,最后一個(gè)是錯(cuò)誤的:
puts "Hello World!";??????????????
puts "Hello World!"???????????????
puts "Hello " \???????????????????
?? "World!";??????????????????????
puts "Hello" +????????????????????
?? "World!";??????????????????????
puts "Hello"?? # 語句至此結(jié)束?????
?? + "World!"; # 無法被解釋的新語句
??? 多個(gè)語句可以用分號(hào)隔開寫到一行里面,這不是很地道的寫法,因?yàn)闀?huì)影響閱讀的流暢。
# 可行,但不漂亮:????????????????
a = 42; b = 15; c = a + b????????
#這樣比較好:?????????????????????
a = 42???????????????????????????
b = 15???????????????????????????
c = a + b????????????????????????
??? Ruby 以兩個(gè)空格作為縮進(jìn)的方式(不用Tab鍵),這是個(gè)推薦習(xí)慣并且應(yīng)該盡可能地得到遵循:
# 非常棒的縮進(jìn)???????????????????
while line = file.readline???????
? if !comment_line(line)?????????
??? lines.add(line)??????????????
? end????????????????????????????
end??????????????????????????????
# oh~,oh~,您這是和外星人學(xué)的吧?
while line = file.readline???????
??? if !comment_line(line)???????
??? ??? lines.add(line)??????????
??? end??????????????????????????
end??????????????????????????????
??? Ruby 提供了全系列的標(biāo)準(zhǔn)類型,如數(shù)字、字符串、正則表達(dá)式、數(shù)組、哈希(Hash),等等。所有這些元素通過類和模塊的方式以備使用,無需在程序(文件)中綁定,它們來自于核心庫并在整個(gè)程序中自動(dòng)生效。
??? 另外一些是以其它類和模塊構(gòu)成系列的標(biāo)準(zhǔn)庫方式以備使用的,例如 Date、Logger、Test::Unit 等等。一旦要自行開發(fā)就必須在每個(gè)程序里通過關(guān)鍵字 require 來明確綁定。于是在 require 后加上或有或無結(jié)尾(.rb)的文件名。
require "date"? # date.rb 用到 Date類??????????????
require "my_class" # my_class.rb 用到MyClass類?????
require "my_module" # my_module.rb 用到 MyModule模塊
??? 對此處文件名的處理不是按絕對路徑,Ruby 會(huì)在所有的標(biāo)準(zhǔn)目錄下尋找這個(gè)文件,它們被包含在全局變量$: 里面,您可以在命令行用 ruby -e "puts $:" 或其它方式得到這些路徑。一個(gè)裝載了類和模塊的程序里的所有名字都可以通過全局變量 $" 輸出。
1.4 注釋
??? 在 Ruby 中注釋行是以#號(hào)開始的,注釋可出現(xiàn)在句首或句尾。
# 下面這行是被注釋掉的???????????
# a = b - c??????????????????????
a = b + c # 注釋到行尾???????????
??? 一個(gè)注釋塊開始于 =begin 結(jié)束于 =end,這幾個(gè)關(guān)鍵字必須在行首,不能有空格。
=begin???????????????????????????
? def my_method??????????????????
??? ...??????????????????????????
? end????????????????????????????
=end?????????????????????????????
1.5 數(shù)字
??? Ruby支持整數(shù)和浮點(diǎn)數(shù)。Ruby 里面沒有原始類型,都是數(shù)字對象。整數(shù)從負(fù)2的30次冪到正2的30次冪 (在64位機(jī)器上從負(fù)2的62次冪到正2的62次冪) 被定義成FixNum類型 超出此范圍的整數(shù)被定義成BigNum類型,類型的劃歸與轉(zhuǎn)換是自動(dòng)完成的,一個(gè)數(shù)字的長度最終由主存來判定。
value = 42 # FixNum???????????????????????????????
big_value = 123456789012345678901234567890 # BigNum
??? 數(shù)字可以用16進(jìn)制、8進(jìn)制或者2進(jìn)制的數(shù)字系統(tǒng)來表示:
# 42?????????????????????????????
0x2A?????????????????????????????
0052?????????????????????????????
b101010??????????????????????????
??? 有相應(yīng)的數(shù)學(xué)運(yùn)算符以供使用,數(shù)字的增減用運(yùn)算符 += 與 -= 來實(shí)現(xiàn), 出自 C 和 Java 的 ++ 與 -- 在 Ruby 里是沒有的。
a = 2????????????????????????????
b = 3????????????????????????????
c = a + b??? # 5?????????????????
c = a - b??? # -1????????????????
c = a / b??? # 0?????????????????
c = 2.0 / b? # 0.666666666666667?
c = a * b??? # 6?????????????????
c = a**b???? # 2*2*2 = 8?????????
a += 1?????? # a = 3?????????????
a -= 1?????? # a = 2?????????????
a++????????? # Ruby里非法????????
??? FixNum與BigNum 繼承于基類 Integer,以下是可用的函數(shù),是與塊(見1.14節(jié))結(jié)合的:
1.upto(3) { [i] puts i }??? # 1 2 3?????????????
3.downto(3) { [i] puts i }? # 3 2 1?????????????
0.step(10,2) { [i] puts i } # 0 2 4 6 8 10??????
3.times { puts *42* }?????? # 42 42 42??????????
??? 浮點(diǎn)數(shù)在 Ruby 里是用 Float 類來表示的。像其它語言一樣,Ruby 里的浮點(diǎn)也有卷折誤差。為了計(jì)算精確(如 合值),建議使用 Ruby 標(biāo)準(zhǔn)庫里的 BigDecimal 類,相對于 Float,這個(gè)類描述了更為豐富的浮點(diǎn)數(shù)并且避開了卷折誤差。
1.6 字符串
?
??? 在 Ruby 里,字符串被放置在兩個(gè)單引號(hào)或雙引號(hào)之間。引號(hào)常會(huì)出現(xiàn)在另一個(gè)引號(hào)里面:
?
str = "Hello"????????? # Hello
str = "Hello 'Thomas'" # Hello 'Thomas'
str = 'Hello'????????? # Hello
str = 'Hello "Thomas"' # Hello "Thomas"
?
??? 字符串可以通過 %q 和 %Q 產(chǎn)生,這是為了避免當(dāng)一個(gè)字符串內(nèi)出現(xiàn)過多的引號(hào)或其它符號(hào)時(shí)會(huì)出現(xiàn)這樣或那樣的錯(cuò)誤。%q 產(chǎn)生一個(gè)被包含在單引號(hào)中的字符串,%Q 產(chǎn)生一個(gè)被包含在雙引號(hào)中的字符串,文本以分隔符為界來限定,分隔符可以是除字母與數(shù)字以外的所有符號(hào)。
%q{a string}
%q(a string)
%Q$a string$
?
??? %Q 可以替換 #{Ausdruck}這樣的表達(dá)式,而%q不能:
?
表格1.1 字符串中帶雙引號(hào)的逃脫符
\a 響鈴 \b 退格 \e 逃脫 \f 換頁 \n 換行 \r 回車 | \s 空格 \t Tab \v 垂直表格跳位 \nnn 八進(jìn)制 \xnn 十六進(jìn)制? \cx Control-x | \C-x???? Control-x \M-x???? Meta-x \M-\C-x? Meta-Control-x \x?????? x #{code}? code |
puts %q{result: #{42.0/3} EUR}???? # result: #{42.0/3} EUR
puts %Q{result: #{42.0/3} EUR}???? # result: 14.0 EUR
?
??? 在花括號(hào)、圓括號(hào)、角括號(hào)的情況下字符串是括號(hào)括起來的部分,其它則是到那個(gè)符號(hào)再次出現(xiàn)為止。字符串也可多行顯示,Ruby 在此并不清除起始空格符。
?
s = %Q@ein String über mehrere?
?Zeile mit "" und '' und durch
? einen Klammeraffen begrenzt@
puts s
=>
ein String über mehrere?
?Zeile mit "" und '' und durch
? einen Klammeraffen begrenzt
puts s.inspect
=>
"ein String \374ber mehrere\n Zeile mit \"\" und '' ...
...und durch \n? einen Klammeraffen begrenzt"
?
???? 一個(gè)表達(dá)式的結(jié)果可以通過#{Ausdruck}插入到一個(gè)字符串中,然而這只有在雙引號(hào)之間有效。
?
"Ergebnis #{42*7/100} %" # Ergebnis?????? #{2.94} %
"Die Anwort ist: #{answer(x)}"??????????? # Die Anwort ist: 42
?
??? 如C與Java所慣用的,特殊符號(hào)由斜杠逃脫,表1.1列舉了所有的特殊符號(hào):
?
"Ein Slash: \\"????????????? # Ein Slash: \
"Er rief: \"Ralf!\""???????? # Er rief: "Ralf!"
'War\'s okey?'?????????????? # War\'s okey?
"Neue\nZeile"??????????????? # Neue
???????????????????????????? #Zeile
'Neue\nZeile'??????????????? # Neue\nZeile
?
??? 兩個(gè)字符串的內(nèi)容可以用 == 方法來比較,與之相對照的是 equal? ,它用來判斷是否是同一個(gè)字符串實(shí)例(參看1.15.5節(jié)):
?
s1 = "Thomas"
s2 = "Thomas"
s3 = "Ralf"
s1 == s2 # => true
s1 == s3 # => false
s1.equal? s1 => true
s1.equal? s2 => false
s1.equal? s3 => false
?
??? 字符串可以用+和<<這兩個(gè)方法連接。使用 * 可實(shí)現(xiàn)多重累加。
?
"Thomas" + "/Ralf"??? # Thomas/Ralf
s = "Thomas"?
s << " und Ralf"????? # Thomas und Ralf
"Ralf " * 2?????????? # Ralf Ralf
?
?
??? 字符串類提供了大量的方法,讓你隨心所欲,下面是幾個(gè)例子;
?
s = "Thomas und Ralf"
s[3]????????????????? # 109
s[3].chr????????????? # m
s[7,3]??????????????? # und
s[0..6]?????????????? # Thomas
?
"Thomas und Ralf".delete("a")???????? # Thoms und Rlf
"Thomas und Ralf".delete("aou")?????? # Thms nd Rlf
"Thomas und Ralf".gsub("und", "oder") # Thomas oder Ralf
"Thomas und Ralf".gsub(/[aou]/, "$")? # Th$m$s $nd R$lf
?
"Thomas und Ralf".index('a')????????? # 4
"Thomas und Ralf".index('a',5)??????? # 12
?
"Thomas und Ralf".split?????????????? # ["Thomas", "und", "Ralf"]
?
??? 為字符串轉(zhuǎn)換成整數(shù)和浮點(diǎn)數(shù)提供兩種途徑,安全一些的是使用核心方法 Integer 和 Float, 它們在出錯(cuò)的時(shí)候拋出異常; 另一種是 String 類的方法 to_i 和 to_f,限制較少 。
"42".to_i??????????? # => 42
nil.to_i???????????? # => 0
"42x".to_i?????????? # => 42
Integer("42")??????? # => 42
Integer(nil)???????? # => 0
Integer("42x")?????? # => 參數(shù)錯(cuò)誤