2011-11-20 93 views
3

在Ruby中,函數可以返回多個*值。 Ruby函數可以確定其調用代碼所期望的返回值數量是多少?Ruby函數可以檢測請求返回值的數量嗎?

例如:

a = f()     # caller expects one return value 
a, b = f()    # caller expects two return values 
a, b, c = f()   # caller expects three return values 

如果我們讓r是預期回報值的數量,是否有可能編寫一個函數f,使得它可以找到r

具體來說,我們怎麼可能改變rcount定義,下面,這樣是通過以下測試:

a, b = rcount() 
puts "#{a},#{b}"   # FAIL, DESIRED: "2,1"  ACTUAL: "1," 
a, b, c = rcount() 
puts "#{a},#{b},#{c}"  # FAIL, DESIRED: "3,2,1" ACTUAL: "1,," 
a, b, c, d = rcount() 
puts "#{a},#{b},#{c},#{d}" # FAIL, DESIRED: "4,3,2,1" ACTUAL: "1,,," 

rcount的定義是這樣的:

def rcount() 
    ret = [] 
    r = nil     # <== Q. IS IT POSSIBLE TO GET r PROGRAMMATICALLY? 
    r ||= 1 
    last = r - 1 
    (0..last).each do |i| 
    ret[i] = r - i 
    end 
    ret 
end 

*其實多回報值是語法糖,真正的返回值是單個數組。所有的Ruby函數都只返回一個值。

+0

爲什麼你使用這個函數'a,b,c = rcount(3)'如果你只能用:'a,b,c =(1..3).to_a' – gustavotkg

+2

可能是一個函數的例子 –

+0

@gustavotkg,'rcount'是一個簡單的函數來演示我的問題灰。這不一定意味着有用。我出於好奇而提出這個問題,並提高了我對Ruby的理解。 – jwfearn

回答

3

不。Ruby環境不會爲您提供該信息。你可以使用一個異常和ParseTree找出調用代碼的樣子,但這是過度的:)

+0

我喜歡'ParseTree'的建議,但我同意它太過矯枉過正。 – jwfearn

8

Ruby函數總是隻有一個返回值。你使用的是Ruby的一個非常漂亮的特性,它允許使用逗號運算符來解構數組。這與splat(asterisk)運算符類似,可用作反向運算符。

考慮這個例子

def rcount(number) 
    # this returns an array containing the 1 till number 
    (1..number).to_a 
end 

array = rcount(3) 
# array is set to [1, 2, 3] 

a, b, c = rcount(3) 
# a is set to 1 
# b is set to 2 
# c is set to 3 

x, y = rcount(3) 
# x is set to 1 
# y is set to 2 
# the last value is thrown away 

r, t, z = rcount(2) 
# r is set to 1 
# t is set to 2 
# z is set to nil 

因此,基本上,沒有必要檢查該號碼或元件在返回的數組,至少對於語法正確性。如果您需要依賴事實,即您始終擁有完全匹配的數組元素數量,則應該檢查使用測試。

只要記住,你實際上在這裏處理數組。由於數組的解構是在函數返回數組之後完成的,因此無法知道之後的值是如何完成的。這與函數調用完全無關。作爲一個最後的建議,如果你實際上會在一個生產軟件中需要這樣的東西,你應該認真重新考慮你的設計,因爲這樣的東西引入了重要的功能耦合。鴨子打字是一件禮物。慷慨地使用它。

+1

一個很好的答案。謝謝。 –

+0

非常好的答案。在rcount(3)示例中有一個小tipo。 y被設置爲2和3被丟棄;) – lucapette

+0

@lucapette:當然,謝謝。我只是糾正它。 –

-1

使用來電者獲取文件和行號。 然後,您可以讀取的代碼行,看看這個函數是如何調用:

def get_line(f,n) 
    File.open(f,'r') do |fh| 
    i = 0 
    fh.each_line do |ln| 
     i+=1 
     return ln if i==n 
    end 
    end 
end 

def f() 
    if caller.first=~/([^:]+):(\d+)/ 
    f,n = $1,$2.to_i 
    line = get_line(f,n) 
    case line 
    when /\w+,\s*\w+\s*=\s*f\(/ 
     return [2, 3] 
    when /=\s*f\(/ 
     return 1 
    else 
     puts 0 
    end 
    end 
end 

f() 
a = f() 
puts "a = #{a}" 
b,c = f() 
puts "b,c = #{b},#{c}" 

輸出是:

0 
a = 1 
b,c = 2,3 

但是,是啊... 這方面是不是紅寶石的一部分語言:

+0

請不要這樣做。永遠。這是令人難以置信的脆弱,不適用於元編程,而且速度很慢。 –