2012年10月25日 星期四

《Ruby Programming-向Ruby之父學程式設計》筆記

一、開始使用 Ruby

1.puts 方法:與 print 不同,顯示的字串以「,」隔開會自動換行。

x = 10
puts("x",  x)

顯示:
x
10

2.p 方法:自動區分字串與數值。顯示的字串以「,」隔開會自動換行。

x = 10
p "x", x

顯示:
"x"
10

*print、puts、p 詳細比較請見「Ruby学习札记(6)-比较print、puts和p方法


3.註解的方式:

(1)
=begin
...
=end

(2)
#


4.讀入其他檔案:

require_relative "檔名"

# 書上是用 require,但我試過會 LoadError。後來是在stackoverflow找到這個解決辦法。

回答者 dominikh 解釋原因是:「The current directory (relative to the main ruby file) is not part of the load paths (the set of paths that require looks in). So you either need to add it to the load path.」
我還是看不太懂...


5.建立雜湊:

雜湊 = { 鍵 => 值 }


6.將物件存進雜湊:

雜湊 ["鍵"] = "值"


7.逐項處理雜湊內容:

雜湊.each{ | 鍵的變數, 值的變數 |
    動作
}

*雜湊沒有固定的順序,不能依存放時的順序取出資料。
詳細雜湊教學請見「Ruby 筆記 - 4 - 雜湊 Hash


8.正規表示法比對:

/樣式/ =~ 欲比對的字串

*在「/樣式/」後加上「i」,則不區分大小寫。


9.取得從命令列傳入的資料:

x = ARGV[0]
print "Hello " ,  x , "!"

輸入 ruby xxx.rb World
顯示:
Hello World!




二、學習基礎

1.變數種類:

(1)區域變數:名稱以小寫字母或「_」起始的變數。

(2)全域變數:名稱以「$」起始的變數。

(3)實體變數:名稱以「@」起始的變數。

(4)類別變數:名稱以「@@」起始的變數。

(5)虛擬變數:「true」、「false」、「self」等特定名稱的變數。


2.取得物件的 ID:

xxx.object_id


3.判斷兩物件變數是否為相同物件(ID 是否相同):

xxx.equal? (yyy)


4.判斷兩物件的值是否相等:

xxx == yyy


5.比較雜湊的內部鍵與外來鍵是否相等:

xxx.eqls? yyy


6.條件判斷:

(1)若條件為真則執行動作:
if 條件
    動作
end

(2)若條件為假則執行動作:
unless 條件
    動作
end

(3)比較多個物件:
case 欲比較的物件
when 值1
    動作
when 值2
    動作
else
    動作
end

*case會使用「===」運算子比對 when 區段所指定的值。當「===」運算子左邊的值是字串數值時,意義與「==」相等;但碰到正規表示式時,意義會等於「=~」;而碰到類別時,則可判斷物件是否為該類別的實體


7.迴圈:

(1)重複處理固定次數:

反覆次數.times{
    動作
}

*使用時機:指定迴圈次數


(2)可自由更改初始值與終止值:
for 變數 in 物件
    動作
end

*使用時機:想自由指定條件時

(3)適用於任何類型迴圈的單純敘述:

while 條件
    動作
end

*使用時機:先判斷再決定是否執行時


(4)與 while 條件判斷相反:
until 條件
    動作
end

*使用時機:想以 while 寫卻會很複雜時

(5)從物件的集合逐項取得資料:
物件.each { | 變數 |
    動作
}

*使用時機:想從物件逐項取得元素時

(6)不斷進行迴圈處理:
loop{
    動作
}

*使用時機:一開始不知道次數範圍限制時


8.迴圈控制指令:

(1)break:停止動作,馬上跳出迴圈。

(2)next:直接跳到迴圈的下一圈。

(3)redo:以相同的條件重新進行這一圈。



9.定義方法:

def 方法名稱
    動作
end


10.查詢物件屬於哪個類別:

xxx.class


11.判斷一物件是否屬於某個類別的實體:

(1)xxx.instance_of?(String)

(2)xxx.is_a?(String)

*is_a? 方法可檢查有繼承關係的子父類別。


12.類別敘述:

class 類別名
    類別定義
end

類別名稱一定要以大寫字母開始


13.定義物件建立後要執行的初始化過程:

def initialize(變數)
    動作
end

*詳細參考:Ruby 使用手冊物件初始化 Object initialization
日本網友寫的比較好理解:initializeメソッド


14.定義物件存取方法:

(1)只定義用來讀取的方法:
attr_reader :xxx

(2)只定義用來寫入的方法:
attr_writer :xxx

(3)定義用來讀取與寫入的方法:
attr_accessor :xxx


15.使用繼承:

class 類別名 < 父類別名
    類別定義
end


16.模組(module)定義:

module 模組名稱
    模組定義
end

模組名稱一定要以大寫字母開始

*使用時機:
  • 兩個類別只是具有相似功能,並不想歸類於相同類型(類別)。
  • 繼承不允許同時有多個父類別,已經繼承別的父類別時,就無法再以繼承的方式加上其他功能。


17.模組(module)的用途:

(1)提供命名空間。

(2)以 Mix-in(將模組混進類別裡):

include 模組名稱


18.在模組內定義方法:

module_function :方法名稱


19.例外處理:

begin
    有可能發生例外的處理動作。
rescue => 變數
    例外發生時的處理措施。
ensure
    無論例外發生與否都會執行的動作。
end

*1.在 rescue 後面指定變數名稱,可得例外物件。例外發生時會自動設定的變數:
  • $!:最後發生的例外物件。
  • $@:最後例外所發生的位置相關資訊。
*2.在 rescue 後面指定類別名稱,可捕捉預想到的例外。



*3.呼叫例外物件的方法:
  • class:例外的種類。
  • message:例外的訊息。
  • backtrace:例外發生的位置資訊。


20.raise 方法:引發例外發生。

*使用時機:自己想要在某些條件下主動產生出新的例外,或再次引發之前捕捉到的例外,將例外交給呼叫端時。


21.raise 的四種形式:

(1)raise 訊息:引發 RuntimeError 例外。指定的字串會被當作新例外物件的訊息。

(2)raise 例外類別:引發指定的例外。

(3)raise 例外類別,訊息:引發指定的例外,且指定的字串會被當作新例外物件的訊息。

(4)raise:若寫在 rescue 區塊外部,則是引發 RuntimeError 例外;寫在 rescue 區塊內則可自動再次引發最後發生的例外($!)




三、使用類別


1.建立陣列:

(1)陣列名 = Array.new(值1, 值2)

(2)陣列名 = %w(值1, 值2)

*使用時機:元素是字串且不含空白時。


2.將物件轉為陣列:

陣列名.to_a


3.取得陣列元素:

(1)從陣列取出索引 n 處一筆元素:

陣列名[n]

(2)將陣列元素「陣列名[n]」直到「陣列名[m]」之間的範圍建立出新的陣列並傳回:

陣列名[n..m]

(3)從陣列元素「a[n]」處開始取得 len 個元素,建立新的陣列並傳回:

陣列名[n, len]


4.取得陣列大小:

array.size


5.逐項處理陣列內容:

陣列.each { | 變數 |
    動作
}



6.插入陣列元素:

陣列名 [索引值, 0] = [欲插入的元素]


7.陣列的交集:

陣列a & 陣列b


8.陣列的聯集:

(1)陣列a | 陣列b

(2)陣列a + 陣列b

*使用「|」結合時,相同的結果只會出現一次;使用「+」結合時,會有重複的結果。


9.陣列的差集:

陣列a - 陣列b


10.操作陣列前端與末端的方法:

(1)加入元素
  • 前端:unshift
  • 末端:push


(2)取出元素
  • 前端:shift
  • 末端:pop


(3)讀取元素
  • 前端:first
  • 末端:last


11.將資料加入陣列:

(1)在陣列 a 前方插入新的元素 item:
a.unshift(item)

(2)在陣列 a 後方插入新的元素 item:
  • a.push(item)
  • a << item

(3)將陣列 a 與陣列 b 連結起來:
  • a + b
  • a.concat(b)

*使用「+」會傳回新的陣列;「concat」為破壞性方法(會直接對接收者的類別造成變更)。

(4)對陣列 a 指定的部分存入元素 item:
  • a[n] = item
  • a[n..m] = item
  • a[n, len] = item


12.從陣列刪除資料:

(1)從陣列 a 中刪除 nil 元素:
  • a.compact
  • a.compact!

(2)從陣列 a 刪除元素 x:
a.delete(x)

(3)從陣列 a 刪除索引 n 處的元素:
a.delete_at(n)

(4)對陣列 a 的每個元素 item 測試,如果區塊的執行結果為真,則從 a 刪除 item:
  • a.reject{ | item | ... }
  • a.reject!{ | item | ... }
  • a.delete_if{ | item | ... }
*delete_if 為破壞性方法。


(5)抽掉陣列 a 指定部分的內容,並替換成新的值:
  • a.slice!(n)
  • a.slice!(n..m)
  • a.slice!(n, len)

(6)刪除陣列 a 重複的元素:
  • a.uniq
  • a.uniq!

(7)除去陣列 a 前端的資料:
a.shift

(8)除去陣列 a 末端的資料:
a.pop

*加上「!」時,為破壞性方法,會直接改寫接收者物件;沒有「!」則是會建立出新陣列的方法。


13.換掉陣列的元素:

(1)對陣列 a 所有元素 item 套用區塊裡的運算,並以運算結果構成新的陣列:
  • a.collect{ | item | ... }
  • a.collect!{ | item | ... }
  • a.map{ | item | ... }
  • a.map!{ | item | ... }

(2)將陣列 a 的元素改寫為 value,當引數只有 1 個時,a 的所有元素都會被換成 value:
a.fill(value)

(3)當有第 2 個引數時,則會改寫第 2 個引述指定之索引 begin 直到陣列尾端:
a.fill(value, begin)

(4)當有第 3 個引數 len 時,則會填滿索引 begin 起算 len 個元素:
a.fill(value, begin, len)

(5)第 2 個引數指定「n..m」範圍時,則將該範圍設為 value:
a.fill(value, n,,m)

(6)將陣列 a 平坦化(當陣列形成巢狀時,將巢狀的元素展開,形成一個大陣列的動作):
  • a.flatten
  • a.flatten!

(7)逆轉陣列 a 中的元素:
  • a.reverse
  • a.reverse!

(8)排序陣列 a 的所有元素。排列的方法,可使用區塊指定。沒有指定區塊時,則使用 <=>運算子進行比較:
  • a.sort
  • a.sort!
  • a.sort{ | i,j | ... }
  • a.sort!{| i, j | ... }

(9)排列陣列 a 的元素。排序時,是以陣列中的元素以區塊指定的方式進行排序:
排序 a.sort_by{ | i | ... }


14.在使用 new 方法建立陣列時,應指定元素與區塊。這樣一來 new 方法就會在設定每個元素時執行區塊。若在區塊裡建立出新的陣列,就不需要擔心每個元素參考到相同的物件。


15.平行處理多個陣列的值:

array1.zip(array2, array3)


16.建立字串含有「""」與「''」字元:

(1)等於「""」圍住的字串:
%Q(字串)

(2)等於「''」圍住的字串:
%q | 字串 |




四、靈活運用 Ruby

1.開啓檔案取得新的 File 物件:

(1)open(檔名, 模式)

(2)File.open(檔名, 模式)


2.模式的種類:

(1)讀取:r

(2)讀取/寫入:r+

(3)寫入:w

*若檔案不存在時會建立新檔;若檔案已存在時,會將檔案長度清到 0。

(4)讀取/寫入:w+

*若檔案不存在時會建立新檔;若檔案已存在時,會將檔案長度清到 0。

(5)追加寫入:a

*檔案不存在時會建立新檔。

(6)追加讀取/寫入:a+

*檔案不存在時會建立新檔。


3.關掉已開啓的檔案:

xxx.close

*對 open 方法傳入區塊時,可以省略 close 方法。這時,IO 物件會作為引數傳入區塊裡。


4.查詢 IO 物件是否已被關閉:

xxx.closed?


5.一次讀入檔案的所有內容:

File.read("xxx.txt")


6.開啟 HTTP、FTP 的 URL:

require "open-uri"


7.確認主控台的輸出:

require "stringio"





推薦網站:

Ruby程式語言入門


Ruby 使用手冊

沒有留言:

張貼留言