2

假设我从 API 取回 JSON 嵌套哈希(或哈希数组)

@example = {"results" = > {{"poop" => "shoop"},{"foo" => {"shizz" => "fizz", "nizzle"=>"bizzle"}}}

上面嵌套哈希的 YAML 标记

  - poop: shoop
  - foo:
    shizz: fizz
    nizzle: bizzle

现在让我们从散列中使用 ActiveRecord 创建一个数据库条目。这工作正常。

Thing.create!(:poop  => @example["results"]["poop"],
                :shizz => @example["results"]["foo"]["shizz"],
                :nizzle=> @example["results"]["foo"]["nizzle"])

但是如果 'foo' 为空或 nil 怎么办?例如,如果一个 API 结果有一个带有“first name”、“last name”# 等的“person”哈希,如果没有数据,“person”哈希通常为空,这意味着它里面的哈希不存在。

@example = {"results" = > {{"poop" => "shoop"},{"foo" => nil }}

  Thing.create!(:poop  => @example["results"]["poop"],
                :shizz => @example["results"]["foo"]["shizz"],
                :nizzle=> @example["results"]["foo"]["nizzle"])

  NoMethodError: You have a nil object when you didn't expect it! 
  You might have expected an instance of Array. 
  The error occurred while evaluating nil.[]

处理这个问题的最佳方法是什么?

4

4 回答 4

4

不久前我遇到了一种nil敏感Hash#get的方法。

class Hash
  def get(key, default=nil)
    key.split(".").inject(self){|memo, key_part| memo[key_part] if memo.is_a?(Hash)} || default
  end
end

h = { 'a' => { 'b' => { 'c' => 1 }}}
puts h.get "a.b.c"    #=> 1
puts h.get "a.b.c.d"  #=> nil
puts h.get "not.here" #=> nil

对于这种 JSON 钻取,它非常方便。

否则你必须做这样的事情:

h['a'] && h['a']['b'] && h['a']['b']['c']

这很糟糕。

于 2011-12-12T19:16:58.707 回答
3

Ruby 2.3.0 引入了一种新方法,在这两者上都调用digHash了,Array它完全解决了这个问题。

value = hash.dig(:a, :b)

nil如果密钥在任何级别丢失,它就会返回。

于 2016-01-06T03:06:03.987 回答
2

如果您使用的是 rails(不确定它是否在 ruby​​ 1.9 中):

h = {"a"=>1}
h.try(:[],"a") #1
h.try(:[],"b") #nil

h2 = {"c"=>{"d"=>1}}
h2.try(:[],"c").try(:[],"d")   #1
h2.try(:[],"a").try(:[],"foo") #nil

# File activesupport/lib/active_support/core_ext/object/try.rb, line 28
def try(*a, &b)
  if a.empty? && block_given?
    yield self
  else
    __send__(*a, &b)
  end
end

于 2011-12-12T19:33:04.620 回答
2

我继续并开始将所有 Hash 结果传递给Hashie Mash。这样,它们的行为就像 Ruby 对象一样,并且像冠军一样响应 nils!

于 2012-01-25T19:23:48.967 回答