鐵 人
Ruby女孩(27):方法的引數傳遞方式,你覺得很簡單嗎?進來小試身手看看XD
2014.Oct.27

今天有兩個小測驗在後面,今天才知道丟引數的規則,所以丟引數測得很High,有興趣的朋友也可以想想看方法是怎麼傳遞引數的(凌晨不睡在測Ruby方法引數的傳遞方式,我應該可以當工程師了XD)

方法的引數

在定義方法時,我們會在方法名稱後面的( )加入引數,引數所接收到的內容可以被送進該方法中,我們今天要來認識引數的規則。

設定引數的預設值

def point(x=3,y=4,z=5)  
  "(#{x},#{y},#{z})"  
end  
  
point  
=> "(3,4,5)"  
  
point(7,8,9)  
=> "(7,8,9)"  

設定引數的預設值很簡單,就是在定義方法時,引數的後面接上等於,再接上預設值即可。但要注意!如果上面的範例沒有設x,y,z的預設值,那直接輸入point的結果會噴錯:

def point(x,y,z)  
  "(#{x},#{y},#{z})"  
end  
  
point  
ArgumentError: wrong number of arguments (0 for 3)  
  
point(5,6,7)  
=> "(5,6,7)"  

因為沒有預設值,所以在呼叫函數的時候要自己在後面加入引數值才可以正常運作。

『引數之中有些有預設值有些沒有,該怎麼辦?』

要記得以下規則:

  • (1) 有預設值的引數一定要『相鄰』!下方為錯誤寫法:
def point(x=3,y,z=5)  
  "(#{x},#{y},#{z})"  
end  

一定要讓有預設值的引數接在一起,所以要改成:

def point(x=3,y=5,z)  def point(x,y=3,z=5)  
  • (2) 在呼叫方法時,給定的引數會由左至右填入,例如:
def point(x,y=3,z=5)  
  "(#{x},#{y},#{z})"  
end  
  
point(2)  
=> "(2,3,5)"  # 只給一個,自動從最左邊的洞填入,因此動到x,其它用預設值。  
  
point(1,7)  
=> "(1,7,5)"  # 給了兩個,從最左邊開始往右邊填,動到x,y,剩下的用預設值。  

或是這樣

def point(x=3,y=5,z)  # 注意本次給預設值的順序跟上面的不一樣。  
  "(#{x},#{y},#{z})"  
end  
  
point(9)  
=> "(3,5,9)"  # 只給一個,結果自動先去找沒有預設值的填入!!!!  
  
point(10,88)    # 這個結果很特別,多多注意!!!!  
=> "(10,5,88)"  
# 給了兩個,由左而右,先填第一個有預設值的,  
# 剩下一個則判斷,如果剛好有一個沒設預設值,就給它!  
  
point(7,49,22)  
=> "(7,49,22)"  # 給三個不用說,就是由左至右乖乖填入。  

[小試身手XD] 來猜猜下方的答案是什麼?

def test(a,b=2,c=3,d=4,e,f)      # 注意有給預設值的引數,只要有相鄰即可!  
  "#{a},#{b},#{c},#{d},#{e},#{f}"  
end  
  
test(55,66,77) = ?  
test(55,66,77,88) = ?  
test(55,66,77,88,99) = ?  

答案明天揭曉(大誤),好啦請拉到這頁最下方就可以看到XD

不定長度的引數串列與陣列

有時候我們希望方法可以接受任意數目的引數,此時我們會替引數前綴一個『*』,此時當引數傳到該位置時,傳的其實是一個陣列,例如:

def idol(name,*skill)  
  puts "我是#{name},我會#{skill}"  
end  
  
idol("Jolin","sing","write","dance")  
=> 我是Jolin,我會["sing", "write", "dance"]  

可以看到上方的例子中,我們傳入了4個引數,第1個是name的引數,第2、3、4個都會被傳入skill中變成陣列!

這個『*』還不只可以這樣用,我們甚至可以直接傳遞一個陣列給idol方法用,只要我們這樣寫:

super_star = ["Matz","ruby1.0","ruby2.0","ruby3.0","ruby4ever"]  
  
idol(*super_star)  
=> 我是Matz,我會["ruby1.0", "ruby2.0", "ruby3.0", "ruby4ever"]  

注意到,『*』可以自動幫我們展開這個陣列,套入idol方法時,就會丟入相對應的位置!超酷!

不過如果剛剛上面沒有加上『*』,會發生什麼事呢?

idol(super_star)  
=> 我是["Matz", "ruby1.0", "ruby2.0", "ruby3.0", "ruby4ever"],我會[]  

他直接把整個陣列都丟入第一個引數的位置了,後面的當做沒傳東西所以變成空陣列!

下方我們來看清楚引數個數丟到方法裡的規則!

def test(a,*b,c)  
  puts "a=#{a}"  
  puts "b=#{b}"  
  puts "c=#{c}"  
end  
  
test(1,2)  
a=1  
b=[]  
c=2    # 因為b加上前綴的*,所以它可以是空陣列。  
  
test(1,2,3)  
a=1  
b=[2]  
c=3  
  
test(1,2,3,4)  
a=1  
b=[2, 3]  
c=4  
  
test(1,2,3,4,5)  
a=1  
b=[2, 3, 4]  
c=5  

啊,引數還沒說完,不過接下來會講到蠻大的重點,所以我們先把今天所說的內容給弄清楚吧!來個終極大考驗好了,預設值、『*』、引數個數差異大・亂・鬥!!

[終極大考驗] 預設值、『*』、引數個數差異之大・亂・鬥

def final_test(a,b=2,c=3,*d,e)  
  puts "a=#{a}"  
  puts "b=#{b}"  
  puts "c=#{c}"  
  puts "d=#{d}"  
  puts "e=#{e}"  
end  
  
final_test(10,11) = ?  
final_test(10,11,12) = ?  
final_test(10,11,12,13) = ?  
final_test(10,11,12,13,14) = ?  
final_test(10,11,12,13,14,15) = ?  

27天!!!

Life is simple. Are you happy? Yes? Keep going. No? Change something.

阿說好要公佈答案的XD白天再公佈在留言好了XD 囧會不會結果都沒有人試XD 沒關係我自己覺得這裡很好玩XDD 現在是凌晨四點多,看Ruby 的書越看越high,好可怕XD


[Answer]

#[小試身手答案XD]
test(55,66,77) => "55,2,3,4,66,77"
test(55,66,77,88) => "55,66,3,4,77,88"
test(55,66,77,88,99) => "55,66,77,4,88,99"
#[終極大考驗答案XD]
final_test(10,11)
a=10
b=2
c=3
d=[]
e=11

final_test(10,11,12)
a=10
b=11
c=3
d=[]
e=12

final_test(10,11,12,13)
a=10
b=11
c=12
d=[]
e=13

final_test(10,11,12,13,14)
a=10
b=11
c=12
d=[13]
e=14

final_test(10,11,12,13,14,15)
a=10
b=11
c=12
d=[13, 14]
e=15

哈哈哈答對了嗎?老實說我自己在final_test錯了,筆記一下:原來有加*的都是最後才丟引數!

Ruby女孩(28):慢慢打開區塊引數的包裝
2014.Oct.28
Ruby女孩(26):別鬧了,方法的( )別亂省!
2014.Oct.26
comments powered by Disqus