我已經Hash通過forwardable模塊在以下源代碼(此處為公共域)中通過委托實作了基本擴展
module OptionsConstants
THIS = lambda { |a| a.itself }
end
require('forwardable')
class AssocHash
extend(Forwardable)
include(Enumerable)
def_delegators(:@table,
:[], :delete, :each, :keys, :values,
:length, :empty?,
:include?, :has_key?, :key?, :member?
)
def self.table_default(whence)
return lambda { |hash, key| raise("Found no key #{key} in #{whence.class} #{whence.object_id}") }
end
def initialize(&keytest)
@table = Hash.new(&self.class.table_default(self))
@keytest = ( keytest || OptionsConstants::THIS )
end
def add(obj, overwrite = false)
usekey=key(obj)
if @table.member?(usekey)
if (obj == @table[usekey])
return obj
elsif ! overwrite
raise("An object is already registered for key #{usekey} in #{self.class} #{self}")
end
end
@table[usekey]=obj
return obj
end
def get(key)
return @table[key]
end
def key(obj)
@keytest.call(obj)
end
end
我仍在研究 Ruby 語言的語法和語意。我想我已經在 Ruby 2.6 類&的檔案中Proc閱讀了一些關于如何在方法引數串列中處理的內容。但是,我不確定我是否完全清楚這種&procarg語法是如何運作的。也許它不像 C 中的指標?
為了實作AsssocHash該類,我希望能夠將兩個 lambda 物件傳遞給該initialize方法,理想情況下,第二個是可選的,這樣第二個 lambda 物件(或通用 proc)將用于提供“默認”proc對于封裝的 hash @table。這將需要提供一個proc給Hash初始化。隨后,default除了@keytest直接在AssocHash.
在為此開發 API 時,在本地,似乎在使用&procarg語法時可能存在一些限制?
- 不能
&procarg在方法簽名中使用兩個? &procarg在方法簽名后不能使用任何 arg嗎?- 在引數串列中不提供常規的必需引數?
目前,我可能只能猜測&在將任何物件/lambda/proc 傳遞給另一種方法時可能會如何使用。雖然在當前實作中添加&到為Hash初始值設定項提供默認 proc 的運算式中可能“有效” ,但坦率地說,我不確定為什么需要它,或者它如何影響Hash初始值設定項接收的內容. 在這段代碼中,這似乎與如何向頂級初始化程式提供任意兩個 proc 運算式的問題無關?
I'm not certain if it's the most accurate terminology, to refer to it as a &procarg. To my own albeit limited understanding of this aspect of Ruby syntax, the & syntax seems to be required for the parameter that provides the value of @keytest to the initializer for AssocHash, such that the @keytest can then be used later in the expression, @keytest.call
Is there some way to provide a second proc to the initializer method, such that then could be used as a proc default for the Hash initializer?
I'll try out a few more iterations on the syntax, here. I'm afraid there may not seem to be a lot of documentation around, about this & qualifier in Ruby method signatures. I'm sure that it's thoroughly documented in the source code, however.
Update
也許&可以不要求傳遞一個lambda或PROC的方法?
我相信以下代碼可能有助于解決這個問題
module TestConstants
NOKEY = lambda { |h,k| return "No key: #{k}" }
end
class Test
def mkhash(fn = TestConstants::NOKEY)
Hash.new(&fn)
end
end
隨后,根據irb:
irb(main)> t = Test.new
=> #<Test:0x0000557c6fe2e460>
irb(main)> h = t.mkhash
=> {}
irb(main)> h[:a]
=> "No key: a"
irb(main)> h = t.mkhash(lambda { |h,k| return "Not found: #{k}" })
=> {}
irb(main)> h[:b]
=> "Not found: b"
如果可以將 lambda 或 proc 傳遞給方法而不用 表示它的引數&,那么早期的AssocHash代碼可能會更新每個 lambda 值將如何傳遞給方法。
也許這與每個 lambda 將如何存盤在任何實體變數中和/或傳遞給Hash建構式無關。
至少,它可能有助于解決如何修改單個類的問題。這個&限定符當然是一個有趣的語法,imo。
uj5u.com熱心網友回復:
Ruby 中的方法可能不會超過一個塊。但是,您可以將任意數量的塊系結為 procs(或 lambdas)并將它們作為常規引數傳遞。你沒有得到很好的塊糖語法 ( do...end),但它作業得很好。
在 Ruby 中,塊(通過{|...| }或do ... end語法傳遞給方法的匿名函式)是“一切都是物件”規則的極少數例外之一。Ruby 允許將回呼或匿名函式傳遞給方法的情況并不少見。您使用塊語法傳遞它,然后可以通過將引數添加為 arg 串列中的最后一個引數來宣告您希望將塊作為 Proc訪問,該&block串列采用您傳遞的匿名函式并將其系結到存盤在變數block。這使您可以呼叫它(通過呼叫block.call)或將其作為普通物件實體(作為block)或作為塊(作為&block)傳遞。您也可以隱式呼叫它yield而不將其系結到 Proc。
def debug(obj = nil, &block)
p [:object, obj]
p [:block, block]
end
def pass_block_as_proc(&foo)
puts "Passing as foo"
debug(foo)
puts "Passing as &foo"
debug(&foo)
end
pass_block_as_proc {}
輸出:
Passing as foo
[:object, #<Proc:0x000055ee3a724a38>]
[:block, nil]
Passing as &foo
[:object, nil]
[:block, #<Proc:0x000055ee3a724a38>]
所以,如果我們想將多個回呼傳遞給一個方法,我們不能依賴匿名塊糖。相反,我們必須將它們作為系結的 Proc 實體傳遞:
def multiple_procs(value, proc1, proc2)
proc2.call(proc1.call(value))
end
puts multiple_procs "foo",
->(s) { s.upcase },
->(s) { s s }
# => FOOFOO
這個鏈接是一些額外的有用閱讀,可以理解塊和程序之間的區別。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/351141.html
