2015-02-23 77 views

回答

5

按照商務部,​​,rng不是Range對象,因爲你可能會想。 rng隨機號碼發生器。

The optional rng argument will be used as the random number generator.

a = (1..10).to_a 
r = Random.new 
r2 = r.dup 
a1 = a.sample(random: r) 
a2 = a.sample(random: r2) 
a1 == a2 # => true 

點是#sample,取其秒參數作爲關鍵字參數。如果我們使用類似foo: 12rng: (1..2)的東西,它會給ArgumentError:未知關鍵字:可選參數只有在您提供值爲random: <any random number generator>時纔可接受。現在,來到你的觀點:

r = 1..3 
a1 = [*1..10].sample(random: r) 
a2 = [*1..10].sample(random: r) 
a1 == a2 # => false 

你逝去的第二個參數爲random: rr必須Random對象或對象來響應#rand。請記住第二個的說法,你告訴#sample,使用你的隨機數發生器而不是默認它在沒有可選參數的情況下使用。

這裏是一個定製實施RNG的:

ob = Object.new 

def ob.to_int 
    5000 
end 

gen_to_int = proc do |max| 
    ob 
end 

class << gen_to_int 
    alias rand call 
end 

ary = (0...10000).to_a 

ary.sample(random: gen_to_int) # => 5000 
ary.sample(random: gen_to_int) # => 5000 
ary.sample(random: gen_to_int) # => 5000 

這會給你的理解與可選參數約#sample。從#test_sample_random中查找更多示例。

更新

How does Array#sample work, if you pass a range as random numbers generator?

要回答這個問題,我想借此TracePoint類的幫助。

trace = TracePoint.new(:c_call) do |tp| 
    p [tp.lineno, tp.defined_class, tp.method_id, tp.event] 
end 

trace.enable do 
    [1,2,3,4,5,66,4].sample(random: 1..3) 
end 
# >> [6, Array, :sample, :c_call] 
# >> [6, Kernel, :rand, :c_call] 
# >> [6, Kernel, :respond_to_missing?, :c_call] 

所以,從上面的調用堆棧,你可以看到 - Array#sample方法被調用。現在在內部,Ruby在Range對象上調用Kernel#rand。現在,(1..3).respond_to?返回false(因爲#rand - 它是Range的a_private_實例方法),這就是爲什麼最終#respond_to_missing?方法已被調用來完成這項工作。

+0

所以這個方法檢查'sample(random:rng)'中的'rng'是否實際上是一個隨機數生成器?你能解釋一下嗎? – zerozero7 2015-02-23 19:47:50

+0

@ zerozero7如何表示?我給你的例子..仍然不服氣.. :-) – 2015-02-23 19:49:20

+0

如何 - 在條款如何知道,提供的價值確實是一個隨機數發生器,而不是範圍對象,例如。我理解你的例子,我不是故意粗魯。只是好奇該方法實際上是否省略了可選參數。 – zerozero7 2015-02-23 19:58:20