ruby示例代码

# 把程式儲存為 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
08      puts "You win!"
09      break
10    else
11      puts "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
   #<SingletonTest:0xbc468>
ruby> test2 = SingletonTest.new
   #<SingletonTest:0xbae20>
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 :vdef v; @v; end
attr_writer :vdef v=(value); @v=value; end
attr_accessor :vattr_reader :v; attr_writer :v
attr_accessor :v, :wattr_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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值