Preface
在 Ruby 中要定義方法,是使用 def 來定義,例如,以下是個求最大公因數的方法定義:
- def gcd(m, n)
- n == 0 ? m : gcd(n, m % n)
- end
- puts gcd(20, 30) # 顯示 10
def 定義方法
在某些語言中,這稱之為定義函式,但在Ruby中def確實是定義物件上的方法,只不過上例中沒有指明方法由誰擁有,呼叫gcd時也沒有指定訊息接收者。你也可以明確指定方法由哪個物件擁有,呼叫時也可以指定訊息接收者。例如:
- obj = Object.new
- def obj.gcd(m, n)
- n == 0 ? m : gcd(n, m % n)
- end
- puts obj.gcd(20, 30) # 顯示 10
- class Object
- # 以下定義了gcd實例方法
- def gcd(m, n)
- n == 0 ? m : gcd(n, m % n)
- end
- private :gcd
- end
之後還會談到,呼叫方法時沒有指定訊息接收者,預設以 self 為訊息接收者,如果是呼叫私有方法,不用也不能撰寫 self(除了一個特例,之後會談到),因為私有方法只能在物件內部使用,不可透過「物件.訊息」的方式呼叫。例如:
以上是 def 定義方法時的細節,實際上初學者,將沒有指定擁有者的方法當作函式來看待,會是比較容易理解的方式。
在 Ruby 中不支援其它語言重載方法的概念(例如Java),也就是在 Ruby 中同一個名稱空間中,不能有相同的方法名稱。如果你定義了兩個方法具有相同的名稱但擁有不同的參數個數,則後者定義會覆蓋前者定義。例如:
由於 Ruby 是動態語言,只需在設計時確認傳入方法的物件所擁有的特性或方法,無需採方法重載中,依型態不同來區別所呼叫方法的部份,至於依參數個數不同來區別的方法重載概念,在 Ruby 中可以使用預設引數(Argument)來解決。例如:
- # encoding: Big5
- def sum(a, b, c = 0)
- a + b + c
- end
- puts sum(10, 20, 30) # 顯示 60
- puts sum(10, 20) # 顯示 30
- def sum(*numbers)
- total = 0
- numbers.each do |number|
- total += number
- end
- total
- end
- puts sum(1, 2) # 顯示 3
- puts sum(1, 2, 3) # 顯示 6
- puts sum(1, 2, 3, 4) # 顯示 10
- def sum(a, b, c)
- a + b + c
- end
- numbers = [1, 2, 3]
- puts sum(*numbers) # 顯示 6
- def some
- [1, 2, 3]
- end
- x, y, z = some
- puts "#{x}, #{y}, #{z}" # 顯示 1, 2, 3
參數中必要引數的部份一徑優先分派引數,所以在 sum(1, 2, 3) 時,a、c、d 為必要引數,所以被指定了1、2、3,因為沒有引數了,所以 b 是空陣列。類似地:
因為 a、c、d 為必要引數,所以 some(1, 2, 3) 時,被指定了 1、2、3,因為沒有引數了,所以 b 會採預設值。如果混用預設引數與接收不定長度引數的參數,則在分配完必要引數之後,接下來再分配預設引數,剩下的才給接受不定長度引數的參數。例如:
接收不定長度引數的參數,必須在預設引數的右邊,否則會發生錯誤。
如果方法的最後一個參數接受雜湊物件,例如:
則{}可以省略,例如
這樣的方法呼叫方式,讓程式原始碼更像是個組態檔案!
則定義方法時,最後一個參數可以使用 * 設定為不定長度引數,如此兩種呼叫方式都可以支援:
在 Ruby 中,方法中還可以定義方法,可以使用區域方法將某個函式中的演算組織為更小的單元,例如,在 選擇排序 的實作時,每次會從未排序部份選擇一個最小值放置到已排序部份之後,在底下的範例中,尋找最小值的演算就實作為區域方法的方式:
- def selection(number)
- # Search index with minimum value among nums[m..-1]
- def min(nums, m, j)
- if j == nums.length
- m
- elsif nums[j] < nums[m]
- min(nums, j, j+1)
- else
- min(nums, m, j+1)
- end
- end
- for i in 0..(number.length - 1)
- m = min(number, i, i+1)
- if m != i
- number[i], number[m] = number[m], number[i]
- end
- end
- end
- number = [1, 5, 2, 3, 9, 7]
- printf("Before sort: %s\n", number)
- selection(number)
- printf("After sort: %s\n", number)
Supplement
* [ DS with Java ] Section 4.1 : Selection Sort
沒有留言:
張貼留言