iT邦幫忙

DAY 27
2

Ruby女孩:10萬.times { puts "為什麼?" }系列 第 27

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

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

※ 方法的引數

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

1. 設定引數的預設值

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

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

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

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


上一篇
Ruby女孩(26):別鬧了,方法的圓括號別亂省!
下一篇
Ruby女孩(28):慢慢打開區塊引數的包裝
系列文
Ruby女孩:10萬.times { puts "為什麼?" }30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
otiann
iT邦新手 2 級 ‧ 2014-10-27 13:27:26

[小試身手答案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錯了,筆記一下:原來有加*的都是最後才丟引數!

0
blackjosh
iT邦見習生 ‧ 2019-02-20 14:21:14

final_test中的*d也算是有預設值[],所以才不會先填入加入的引數

我要留言

立即登入留言