def 定義方法

文章推薦指數: 80 %
投票人數:10人

在Ruby中要定義方法,是使用def來定義,例如,以下是個求最大公因數的方法定義: def gcd(m, n) n == 0 ? m : gcd(n, m % n) end puts gcd(20, 30) # 顯示10 回Ruby目錄 在Ruby中要定義方法,是使用def來定義,例如,以下是個求最大公因數的方法定義: defgcd(m,n)n==0?m:gcd(n,m%n)endputsgcd(20,30)#顯示10 在上例中,gcd是函式名稱,m與n為參數(Parameter)名稱,如果要傳回值可使用return,如果沒有指定return,則以最後一個陳述句執行結果的傳回值,作為函式的傳回值。

在某些語言中,這稱之為定義函式,但在Ruby中def確實是定義物件上的方法,只不過上例中沒有指明方法由誰擁有,呼叫gcd時也沒有指定訊息接收者。

你也可以明確指定方法由哪個物件擁有,呼叫時也可以指定訊息接收者。

例如。

obj=Object.newdefobj.gcd(m,n)n==0?m:gcd(n,m%n)endputsobj.gcd(20,30)#顯示10 上例中,為obj定義了gcd單例方法(Singletonmethod)。

如果在頂層環境中定義方法時,沒有指定方法由哪個物件擁有,則方法是由Object擁有的私有(private)實例方法(Instancemethod)。

例如,上面第一個範例的gcd方法,相當於以下寫法: classObject#以下定義了gcd實例方法defgcd(m,n)n==0?m:gcd(n,m%n)endprivate:gcdend 定義在頂層的方法沒有指定擁有者時,就是Object擁有的私有實例方法,Object為所有類別的父類別,因此任何類別或模組定義中,就可以直接呼叫。

之後還會談到,呼叫方法時沒有指定訊息接收者,預設以self為訊息接收者,如果是呼叫私有方法,不用也不能撰寫self(除了一個特例,之後會談到),因為私有方法只能在物件內部使用,不可透過「物件.訊息」的方式呼叫。

例如: >>defsome >>    print"some...." >>end =>nil >>some some....=>nil >>self.some NoMethodError:privatemethod`some'calledformain:Object        from(irb):10        fromC:/Winware/Ruby192/bin/irb:12:in`

' >> 以上是def定義方法時的細節,實際上初學者,將沒有指定擁有者的方法當作函式來看待,會是比較容易理解的方式。

在Ruby中不支援其它語言重載方法的概念(例如Java),也就是在Ruby中同一個名稱空間中,不能有相同的方法名稱。

如果你定義了兩個方法具有相同的名稱但擁有不同的參數個數,則後者定義會覆蓋前者定義。

例如: >>defsum(a,b) >>    a+b >>end =>nil >>defsum(a,b,c) >>    a+b+c >>end =>nil >>sum(1,2,3) =>6 >>sum(1,2) ArgumentError:wrongnumberofarguments(2for3)        from(irb):29:in`sum'        from(irb):33        fromC:/Winware/Ruby192/bin/irb:12:in`
' >> 由於Ruby是動態語言,只需在設計時確認傳入方法的物件所擁有的特性或方法,無需採方法重載中,依型態不同來區別所呼叫方法的部份,至於依參數個數不同來區別的方法重載概念,在Ruby中可以使用預設引數(Argument)來解決。

例如: #encoding:Big5defsum(a,b,c=0)a+b+cendputssum(10,20,30)#顯示60putssum(10,20)#顯示30 像sum這種加總數字的需求,事先可能不知道要傳入的引數個數,可以在定義方法的參數時使用*,表示該參數接受不定長度引數。

例如: defsum(*numbers)total=0numbers.eachdo|number|total+=numberendtotalendputssum(1,2)#顯示3putssum(1,2,3)#顯示6putssum(1,2,3,4)#顯示10 你傳入方法的引數,會被收集在一個陣列中,再設定給numbers參數。

在陣列型態中提過,*可以用來拆解陣列,將元素逐一指定給數個變數,這個語法也適用在方法的參數指定,你可以將一個陣列傳入,只要在傳入時加上*,則陣列中每個元素會自動指定給各個參數。

例如: defsum(a,b,c)a+b+cendnumbers=[1,2,3]putssum(*numbers)#顯示6 如果方法中傳回陣列,也可以如此指定。

例如: defsome[1,2,3]endx,y,z=someputs"#{x},#{y},#{z}"#顯示1,2,3 方法中的參數若沒有預設引數,或使用*設定接受不定長度引數,則呼叫方法時該參數不一定要接收引數。

如果方法中的參數混用必要引數與非必要引數,則引數一律優先滿足必要引數的參數。

例如: >>defsome(a,*b,c,d) >>   pa,b,c,d >>end =>nil >>some(1,2,3,4,5) 1 [2,3] 4 5 =>[1,[2,3],4,5] >>some(1,2,3,4) 1 [2] 3 4 =>[1,[2],3,4] >>some(1,2,3) 1 [] 2 3 =>[1,[],2,3] >> 參數中必要引數的部份一徑優先分派引數,所以在sum(1,2,3)時,a、c、d為必要引數,所以被指定了1、2、3,因為沒有引數了,所以b是空陣列。

類似地: >>defsome(a,b=10,c,d) >>    pa,b,c,d >>end =>nil >>some(1,2,3,4) 1 2 3 4 =>[1,2,3,4] >>some(1,2,3) 1 10 2 3 =>[1,10,2,3] >> 因為a、c、d為必要引數,所以some(1,2,3)時,被指定了1、2、3,因為沒有引數了,所以b會採預設值。

如果混用預設引數與接收不定長度引數的參數,則在分配完必要引數之後,接下來再分配預設引數,剩下的才給接受不定長度引數的參數。

例如: >>defsome(a,b=10,*c,d) >>    pa,b,c,d >>end =>nil >>some(1,2,3,4,5) 1 2 [3,4] 5 =>[1,2,[3,4],5] >>some(1,2,3,4) 1 2 [3] 4 =>[1,2,[3],4] >>some(1,2,3) 1 2 [] 3 =>[1,2,[],3] >>some(1,2) 1 10 [] 2 =>[1,10,[],2] >> 接收不定長度引數的參數,必須在預設引數的右邊,否則會發生錯誤。

如果方法的最後一個參數接受雜湊物件,例如: >>defconfig(name,props) >>    puts"name=#{name}" >>    putsprops >>end =>nil >>config"system",{"p1"=>"v1","p2"=>"v2","p3"=>"v3"} name=system {"p1"=>"v1","p2"=>"v2","p3"=>"v3"} =>nil >> 則{}可以省略,例如: >>config"system", ?>           "p1"=>"v1", ?>           "p2"=>"v2", ?>           "p3"=>"v3" name=system {"p1"=>"v1","p2"=>"v2","p3"=>"v3"} =>nil >>config"system", ?>           :p1=>"v1", ?>           :p2=>"v2", ?>           :p3=>"v3" name=system {:p1=>"v1",:p2=>"v2",:p3=>"v3"} =>nil >>config"system", ?>           p1:"v1", ?>           p2:"v2", ?>           p3:"v3" name=system {:p1=>"v1",:p2=>"v2",:p3=>"v3"} =>nil >> 這樣的方法呼叫方式,讓程式原始碼更像是個組態檔案,廣用於如Rails之類的框架中。

通常提供這樣機制的方法: config"system",           "p1"=>"v1",           "p2"=>"v2",           "p3"=>"v3" 也可以提供另一種設定方式: config"system",           "p1","v1",           "p2","v2",           "p3","v3" 則定義方法時,最後一個參數可以使用*設定為不定長度引數,如此兩種呼叫方式都可以支援: >>defconfig(name,*props) >>    puts"name=#{name}" >>    putsprops >>end =>nil >>config"system", ?>           "p1"=>"v1", ?>           "p2"=>"v2", ?>           "p3"=>"v3" name=system {"p1"=>"v1","p2"=>"v2","p3"=>"v3"} =>nil >>config"system", ?>           "p1","v1", ?>           "p2","v2", ?>           "p3","v3" name=system p1 v1 p2 v2 p3 v3 =>nil >> 在Ruby中,方法中還可以定義方法,可以使用區域方法將某個函式中的演算組織為更小的單元,例如,在選 擇排序的實作時,每次會從未排序部份選擇一個最小值放置到已排序部份之後,在底下的範例中,尋找最小值的演算就實作為區域方法的方式: defselection(number)#找出未排序中最小值defmin(nums,m,j)ifj==nums.lengthmelsifnums[j]



請為這篇文章評分?