Ruby 中的集合 - 是否有集合 class 类似于 Set 但具有 Hash 的成员访问权限?

Collections in Ruby - is there a collections class like Set but with the member access of Hash?

在阅读了彼得·琼斯的书 Effective Ruby 中的 Collections 章节后,集合 class似乎提供了一种有趣的 Hash 替代方法。关于集合 class,琼斯说:

It’s a lot like its mathematical cousin, a collection of unordered unique elements with operations such as union, intersection, and subset/superset testing.

我唯一担心的是 Set class 是否可能不提供对实际成员对象的直接访问。

目前,我正在尝试使用 Set(或 Set 之类的东西)来实现天真的 OptionSet API,这样 OptionSet 可能是 OptionValueOption 类型,后者是 Option 的子 class。 API 可能需要访问存储在每个 OptionSet 各自集合中的对象——无论是存储在单独的哈希、数组、其他容器对象中,还是通过某些方法存储在 OptionSet 中继承的实现,例如 Set 作为 superclass.

我想在 OptionSet 中使用 Set,或者只是将 OptionSet 实现为 Set 的子 class。但是,如果 Set 可能不提供对成员对象的直接访问,一旦存储 - 没有遍历 Set 中的每个成员对象,直到找到任何表面上的匹配(例如一旦找到任何 Option 或集合中的 ValueOption,这样“匹配项”就有一个等效的 Option.name,通常是一个符号)——也许有更有效的替代方法?

我会提供示例代码,但 OptionSet 的实现目前不可用。在伪代码中,我试图将 OptionSet#getopt(name) 实现为 return 存储在 OptionSet 中的任何命名 Option 对象的值,如果没有存储此类选项,则为 false。

#getopt 方法将调用 self.getoptObj(name),这是一种受保护的方法,需要访问集合中命名选项的实际 Option 对象。除了那部分实现,否则Set可能直接适合。

在任何类似于 Scheme 的语言中,Ruby 标准库可能不提供 AssociativeList class, 本身 ?简单地说,我想知道是否有像 Set 这样的 class —— 即使用 Set 中的集合论方法 —— 但具有 Hash?[=46 的成员访问权限=]

更新

我已经尝试实现 MappedSet class,至少在伪代码中,例如使用实例 Hash 值来存储通用“键”和成员对象。但是,我认为这对于 Set 的国际存储来说是多余的。也许我应该简单地扩展 Hash.

如果你想创建一个像 class 这样的散列,你可以使用 DelegateClass:

class FalsyHash < DelegateClass(Hash)
  def initialize(hash)
    super.tap { |result| result.default = false }
  end
end
irb(main):001:0> f = FalsyHash.new(a: :b)
=> {:a=>:b}
irb(main):002:0> f[:b]
=> false
irb(main):003:0> f.is_a?(Hash)
=> false     

这基本上只是一个 class,它采用所提供的 class 的一个实例并将其包装起来,以便转发方法调用。由于它实际上不是哈希的实例,因此我们避免了核心方法检查我们是否正在处理哈希时发生的陷阱,如果我们使用哈希的子 class 就会发生这种情况。

Delegator、SimpleDelegator 和 Forwardable 可以实现相同的目的 - DelegateClass 只是一种直接的包装方式 classes。

您还可以通过使用模块扩展 Hash 的特定实例来扩充它们:

module Reversable
  def reverse
    transform_values { |v| v.respond_to?(:reverse) ? v.reverse : v }
  end
end

# Guess what this returns for a cookie
{ foo: 'olleH', bar: nil, baz: 'dlrow' }.extend(Reversable)
                                        .reverse
                                        .values
                                        .compact
                                        .sort     
                                        .join(" ")