ruby示例代码

红太狼 2024-02-17 15:05 151阅读 0赞

# 把程式儲存為 guess.rb

words = [‘foobar’, ‘baz’, ‘quux’]

secret = words[rand(3)]

print “guess?”

while guess = STDIN.gets

guess.chop!

if guess == secret

puts “You win!”

break

else

puts “Sorry, you lose.”

end

print “guess?”

end

puts “The word was “ + secret + “.”

==================================================================================

# 需要 ANSI 終端機!

st = “\033[7m”
en = “\033[m”

puts “Enter an empty string at any time to exit.”

while true
print “str> “; STDOUT.flush; str = gets.chop
break if str.empty?
print “pat> “; STDOUT.flush; pat = gets.chop
break if pat.empty?
re = Regexp.new(pat)
puts str.gsub(re,”#{st}\\&#{en}“)
end

==================================================================================

陣列可用 join 轉換為字串,字串可用 split 轉換為陣列:

ruby> str = ary.join(“:”)
“1:2:3”
ruby> str.split(“:”)
[“1”, “2”, “3”]

01 words = [‘foobar’, ‘baz’, ‘quux’]
02 secret = words[rand(3)]
03
04 print “guess?”
05 while guess = STDIN.gets
06 guess.chop!
07 if guess == secret
08puts “You win!”
09break
10 else
11puts “Sorry, you lose.”
12 end
13 print “guess?”
14 end
15 puts “the word is “+ secret + “ . “

程式中,使用了 while 這個新的控制結構。若指定的條件為真時,就會重複運行 while 與其對應的 end 之間的程式碼。這個範例中,guess=STDIN.gets 既是一個有動作的敘述(收集使用者輸入的一行內容,並儲存為 guess),也是一項判斷條件(若沒有輸入任何內容,guess 即等於整個 guess=STDIN.gets 表示式的值,而這個值是 nil,會讓 while 停止迴圈。)

STDIN 是標準輸入 (standard input) 物件。一般來說,guess=gets 的功能與 guess=STDIN.gets 一樣。

第 2 行的 rand(3) 會傳回 0 至 2 間的一個亂數 ( random number), 用來提取陣列 words 中的一個元素。

第 5 行中,我們利用方法 STDIN.gets,從標準輸入中提取一行內容。提取時若出現 EOF(檔案結尾),gets 會傳回 nil。因此 while 程式碼會不斷重複,直到遇到代表結束輸入的 ^D(DOS/Windows 中則是 ^ZF6)。

第 6 行中 guess.chop! 會刪除 guess 後的最後一個字元;在本例中這是一個換行 (newline) 字元,這是因為 gets 會包含使用者按下的 Return 鍵,這是我們不感興趣的。

在第 15 行中輸出謎底。我們將謎底寫為三個字串將之相加在一起;這與將 secret 寫為 #{secret} 的單一字串效果相同,清楚顯示這是將要計算的變數,而不只是逐字輸出而已:

==================================================================================

加入驚嘆號就是「破壞性的」(destructive) chop, 那兩者有甚麼差別呢?在 Ruby 中,我們一般在方法名稱後加上 ‘!‘ 或 ‘?‘。驚嘆號(! 有時讀作 “bang!”)代表具有破壞性,即會改變所接觸物件的值。chop! 會直接影響字串,但 chop 則會提供一個刪減後的版本,而不影響原本的物件。以下將闡釋兩者的差異。

ruby> s1 = “forth”
“forth”
ruby> s1.chop!# 這改變了 s1。
“fort”
ruby> s2 = s1.chop # 這將變更後的版本置於 s2,
“for”
ruby> s1# ⋯⋯而不影響 s1。
“fort”

你也會看見有 chompchomp!。提供更多選擇性:字串結尾是一個換行字元時,結尾才會刪掉。例如:"XYZ".chomp!,並不會有任何效果。記住兩者差別的技巧就是,想像人或動物吃東西前,總會先嘗嘗味道,才會一口咬下去,而不像斧頭那樣隨便就砍下去。

==================================================================================

case 內部使用關聯運算子 (relationship operator) ===,同一時間檢查數個條件。為保持 Ruby 的物件導向特質,出現在 when 條件內的物件會以 === 適當解釋。例如,以下程式碼會測試字串是否等於第一個 when 的字串,再測試是否符合第二個 when 的正規表示式。

ruby> case ‘abcdef’
| when ‘aaa’, ‘bbb’
| puts “aaa or bbb”
| when /def/
| puts “includes /def/“
| end
includes /def/
nil

==================================================================================

Ruby 有個特別的變數稱為 self,指向現在的物件(也就是呼叫此方法的物件)。因為經常使用 “self.“,所以在物件本身呼叫方法時,可以省略:

self.method_name(args…)

即等同於

method_name(args…)

我們可以把傳統的函數呼叫 (function call) 當做是物件 method,只是省略了 self 呼叫。因此 Ruby 可稱為純物件導向語言(編註:因為所有函式都在物件之中)。當然,這個函數呼叫與其他程式語言的函數非常類似,這也方便了那些不明白 Ruby 中函數呼叫就是物件方法的人。如果必要的話,我們會說 “函數 (functions)“,以跟物件方法(object methods)做區別。

==================================================================================

實例 (instance) 的行為由其所屬的類別決定,但有時候我們知道某個實例應該具有特定行為。大部分語言中,我們必須大費周章定義其他類別,但只能實例化 (instantiate) 一次。而 Ruby 能為所有物件提供自己的方法。

ruby> class SingletonTest
| def size
| 25
| end
| end
nil
ruby> test1 = SingletonTest.new
#
ruby> test2 = SingletonTest.new
#
ruby> def test2.size
| 10
| end
nil
ruby> test1.size
25
ruby> test2.size
10

本例中,test1test2 屬於同一類別,但 test2 具有重新定義的 size 方法,因此兩者的行為會不一樣。只給予單一物件的方法稱為單件方法 (singleton method)

單件方法經常用於圖形使用者介面 (graphic user interface, GUI) 的元素,當按下不同按鈕,就會執行不同動作。

單件方法並不是 Ruby 獨有的,CLOS、Dylan 等也有。有些語言例如 Self 及 NewtonScript 更只有單件方法。這有時會稱為原型 (prototype-based) 語言。

==================================================================================

下例中,defined? 是檢查識別符 (identifier) 有否定義的運算子。若已定義,就會傳回該識別符的描述,否則就傳回 nil。如你所見,bar 的作用域位於迴圈內;若迴圈結束,bar 就變成未定義了。

ruby> foo = 44; puts foo; defined?(foo)
44
“local-variable”
ruby> loop{bar=45; puts bar; break}; defined?(bar)
45
nil

==================================================================================

簡單使用存取器

因為不少實例變數都需要存取器方法,因此 Ruby 提供了一些快捷的方式。
























快捷方式 效果
attr_reader :v def v; @v; end
attr_writer :v def v=(value); @v=value; end
attr_accessor :v attr_reader :v; attr_writer :v
attr_accessor :v, :w attr_accessor :v; attr_accessor :w 

==================================================================================

將假設 (assumption) 改為需求 (requirement)

有時候,預設值並不大合理, 例如有「水果預設種類」這種東西嗎?比較理想的是,要求創造水果時,即指定每件水果的種類。因此,我們要在 initialize 方法中加入一個形式引數 (formal argument), 供應至 new 的引數其實都傳遞至 initialize

ruby> class Fruit
| def initialize( k )
| @kind = k
| @condition = “ripe”
| end
| end
nil
ruby> f5 = Fruit.new “mango”
“a ripe mango”
ruby> f6 = Fruit.new
ERR: (eval):1:in `initialize’: wrong # of arguments(0 for 1)

==================================================================================

組織你的程式碼

Ruby 具有高層級的動態性 (dynamism),指的是類別、模組、方法只會在定義它們的程式碼運作後才存在。如果你習慣使用較靜態的語言編寫程式的話,有時候可能會出現驚喜。

# 以下結果會導致 “undefined method”(未定義方法)錯誤:

puts successor(3)

def successor(x)
x + 1
end

雖然直譯器執行前,會檢查整份腳本文件的語法,但 def successor ... end 程式碼需要真的運作,才能建立 successor 方法。因此,排列腳本的次序將是關鍵。

发表评论

表情:
评论列表 (有 0 条评论,151人围观)

还没有评论,来说两句吧...

相关阅读