在 Ruby 中,什么是判断变量是 Hash 还是 Array 的优雅方法?

为了检查 @some_var是什么,我正在做一个

if @some_var.class.to_s == 'Hash'

我确信有一个更优雅的方法来检查 @some_varHash还是 Array

127846 次浏览

你可以使用 instance_of?

例如:

@some_var.instance_of?(Hash)

你可以这样做:

@some_var.class == Hash

或者类似这样的东西:

@some_var.is_a?(Hash)

值得注意的是“ is _ a?”如果该类位于对象祖先树中的任何位置,则。例如:

@some_var.is_a?(Object)  # => true

如果@some _ var 是散列或其他源自 Object 的类的实例,则上述条件为真。那么,如果您希望对类类型进行严格匹配,使用 = = 或 instance _ of?方法可能就是你要找的。

irb(main):005:0> {}.class
=> Hash
irb(main):006:0> [].class
=> Array

通常在红宝石中,当你在寻找“类型”时,你实际上想要的是“鸭子类型”或“像鸭子一样嘎嘎叫吗?”.你会看到它是否对某种方法有反应:

@some_var.respond_to?(:each)

可以在@some _ var 上迭代,因为它响应: each

如果你真的想知道类型,如果它是哈希或数组,然后你可以做:

["Hash", "Array"].include?(@some_var.class)  #=> check both through instance class
@some_var.kind_of?(Hash)    #=> to check each at once
@some_var.is_a?(Array)   #=> same as kind_of
Hash === @some_var #=> return Boolean

这也可以与 case 语句一起使用

case @some_var
when Hash
...
when Array
...
end

首先,字面上的问题的最佳答案是

Hash === @some_var

但是这个问题真的应该通过在这里展示如何使用 Duck 键入来回答。 这取决于你需要什么样的鸭子。

@some_var.respond_to?(:each_pair)

或者

@some_var.respond_to?(:has_key?)

甚至

@some_var.respond_to?(:to_hash)

可能是正确的,这取决于申请。

我用这个:

@var.respond_to?(:keys)

它适用于 Hash 和 ActiveSupport: : HashWithIndifferent entAccess。

在实践中,您通常希望根据变量是 Array 还是 Hash 而采取不同的行为,而不仅仅是告诉。在这种情况下,优雅惯用语如下:

case item
when Array
#do something
when Hash
#do something else
end

请注意,不要在 item上调用 .class方法。

如果您想测试一个对象是严格的还是扩展了 Hash,请使用:

value = {}
value.is_a?(Hash) || value.is_a?(Array) #=> true

但是为了让 Ruby 的 Duck 键入变得有价值,你可以这样做:

value = {}
value.respond_to?(:[]) #=> true

当您只想使用 value[:key]语法访问某些值时,它非常有用。

请注意,Array.new["key"]将提高一个 TypeError