def 定義方法
文章推薦指數: 80 %
在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`
在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`
例如:
#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]
延伸文章資訊
- 1定義方法_百度百科
定義方法是揭示概念內涵的邏輯方法。通過某概念所反映的對象的本質屬性來説明該概念。從邏輯結構上看,定義包括三個部分:①被定義項,即其內涵需要明確的概念;②定義 ...
- 2方法學- 維基百科,自由的百科全書
定義
- 3方法定義- JavaScript
自ECMAScript 2015 開始,引入了一種於物件初始器(objects initializers)中定義方法的簡短語法。是一個將函式指派予方法名稱的簡便方式。
- 4方法(電腦科學) - 维基百科,自由的百科全书
在物件導向程式設計中,方法(英語:Method;德語:Methode; 法語:Méthode)指的是類別(所謂的類別方法、靜態方法或工廠方法)、或者是物件(所謂的實體方法)兩者 ...
- 5重新定義實作
對 drawFight() 方法而言,只知道傳進來的會是一種 Role 物件,所以編譯器也只能檢查你呼叫的方法, Role 是不是有定義,顯然地, Role 目前並沒有定義 fight() 方法...