【发布时间】:2021-11-04 23:17:46
【问题描述】:
我已经通过forwardable 模块在Hash 上实现了一个基本扩展,在以下源代码中(此处为公共域)
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 语言的语法和语义。我想我已经在documentation for the Proc class in Ruby 2.6 中阅读了一些关于如何在方法参数列表中处理& 的内容。但是,我不确定我是否完全清楚 &procarg 语法如何运作。也许它不像 C 中的指针?
为了实现 AsssocHash 类,我希望能够将两个 lambda 对象传递给 initialize 方法,理想情况下第二个是可选的,这样第二个 lambda 对象(或通用 proc)将是然后用于为封装的哈希@table 提供一个“默认”过程。它需要作为proc 提供给Hash 初始化程序。随后,除了在AssocHash 中直接使用的@keytest proc 之外,还可以从任何调用API 提供default proc。
在本地为此开发 API 时,似乎在使用 &procarg 语法时可能存在一些限制?
- 不能在方法签名中使用两个
&procarg? - 不能在方法签名中的
&procarg之后使用任何 arg? - 没有在参数列表中提供常规的必需参数?
目前,我可能只能猜测在将任何对象/lambda/proc 传递给另一个方法时如何使用&。虽然在当前实现中将& 添加到表达式中以为Hash 初始化程序提供默认过程可能已经“刚刚工作”,但坦率地说,我不确定为什么需要它,或者如何它会影响 Hash 初始化程序接收的内容。这似乎与如何在此代码中向顶级初始化程序提供任何两个 proc 表达式的问题相切?
我不确定它是否是最准确的术语,将其称为&procarg。尽管我自己对 Ruby 语法的这一方面的理解有限,但将 @keytest 的值提供给 AssocHash 的初始化程序的参数似乎需要 & 语法,这样 @keytest 就可以是稍后在表达式中使用,@keytest.call
有没有办法为初始化方法提供第二个过程,这样就可以用作Hash 初始化方法的默认过程?
我将在此处尝试对语法进行更多迭代。恐怕周围似乎没有很多文档,关于 Ruby 方法签名中的这个 & 限定符。不过,我确信它已在源代码中详细记录。
更新
也许& 可能不需要将 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。
【问题讨论】: