【问题标题】:How to detect an array- or set-like value while avoiding type checks如何在避免类型检查的同时检测类似数组或集合的值
【发布时间】:2011-07-20 20:41:30
【问题描述】:

我有一个接受参数的方法,该参数可以是类数组/集合对象或哈希。该方法的要点如下:

def find(query = {})
  if Array === query or Set === query
    query = {:_id => {'$in' => query.to_a}}
  end
  mongo_collection.find(query)
end

该方法将接受一组 ID 对象并将其转换为 MongoDB 的哈希条件。

上面代码的两个问题:

  1. 如果标准库不需要“set”,它将失败。我不想要求依赖项只是为了执行检查。
  2. 我不想进行严格的类型比较。我想接受任何类似数组或类似集合的值并将其转换为带有to_a 的值数组。

您将如何执行此检查?一些注意事项:

  1. 我可以检查to_ary 方法,但Set 没有响应to_ary。实现此方法的对象本质上应该是数组,我同意 Set 本质上不是数组。见Consequences of implementing to_int and to_str in Ruby
  2. 我无法检查 to_a,因为 Hash 会响应它
  3. Array 和 Set 通用但 Hash 不通用的方法有:

    [:&, :+, :-, :<<, :collect!, :flatten!, :map!, :|]
    

我决定这样做:

query = {:_id => {'$in' => query.to_a}} if query.respond_to? :&

因为交集很可能是一个类似集合的对象的运算符。但我不确定。

【问题讨论】:

  • 基本上你在谈论鸭式打字。如果对象可以像数组一样工作,您并不关心它是什么。因此,将.to_a 添加到对象中,看看它是否可以转换为数组。如果你想要一个散列,你可能想要转换为一个数组然后构造一个散列:Hash[*array.to_a.flatten]。此时,调用者的工作是要求适当的类,而不是你。

标签: ruby mongodb types set duck-typing


【解决方案1】:

这是我的看法:

if not Hash === query and query.respond_to? :to_a

我只是在检查to_a,这是我感兴趣的唯一方法,但还要确保它不是 Hash 对象。我对 Hash 使用了严格的类型检查,但这只是因为这是最不可能作为一个完全独立的类传递的对象,它基本上是一个哈希。

【讨论】:

    【解决方案2】:

    尝试找出查询是否类似于 Hash 怎么样?

    def find(query = {})
      query = {:_id => {'$in' => query.to_a}} unless query.respond_to?(:has_key?)
      mongo_collection.find(query)
    end
    

    如果对象响应 has_key?,则可以合理地预期该对象将是一个 Hash 或 Hash?。

    【讨论】:

    • 这似乎是解决这个具体问题的最优雅的解决方案,但没有回答最初的一般问题:“如何检测数组或类似集合的值”。哦,好吧
    【解决方案3】:

    检查是否定义了 Set 将解决您的第一个问题。其次,您可以检查查询类的祖先以查看 Array 是否在其中,但这可能不会捕获所有“类似数组”的对象。我可能不会检查是否存在测试数组的方法,因为您正在测试名称,而不是行为。 Arel 特别响应(或在它被弃用之前)&,但这种类型的对象不会像你想要的那样工作。

    【讨论】:

      【解决方案4】:

      我个人认为...

      def find(query = {})      
        mongo_collection.find(query_formatter(query))
      end
      
      def query_formatter(query)
        if query.respond_to?(:to_a) && !query.kind_of?(Hash)
          {:_id => {'$in' => query.to_a}}
        else
          query
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-22
        • 2018-05-05
        相关资源
        最近更新 更多