Ruby 密钥被替换,而不是创建新密钥

Ruby key getting replaced, instead of a new key created

ruby 2.5

我有以下代码:

test = {'primer' => 'grey'}
layers = ["tan","burgundy"]
fillers = ["blue","yellow"]
layers.each do |l|
    fillers.each do |f|
      test[l] = {} if !test.respond_to?(l)
      test[l][f] = {} if !test[l].respond_to?(f)
    end
end

当我在 irb 中 运行 时,我得到以下信息:

{"primer"=>"grey", "tan"=>{"yellow"=>{}}, "burgundy"=>{"yellow"=>{}}}

我期待:

{"primer"=>"grey", "tan"=>{"blue"=>{},"yellow"=>{}}, "burgundy"=>{"blue"=>{},"yellow"=>{}}}

为什么第一个 respond_to 生成密钥,而第二个 respond_to 生成密钥,而第二个替换前一个密钥?

我错过了什么?

表达式

test.respond_to?(l)

没有意义。 l 是一个字符串,并且 respond_to? returns 如果接收方具有此字符串表示的名称的方法则为真。由于接收者是一个 Hash 并且 Hash 没有方法 Hash#tan 和 Hash#burgundy,所以测试总是失败。

也许你想做一个 test.has_key?(l) 而不是....

假设您有散列 {a: 1},拥有键 :a 不会使散列对象响应 :ahash.respond_to?(:a) 仍然会 return false。你想检查一个密钥是否存在,这可以使用 has_key?/key?.

来完成
layers.each do |l|
  fillers.each do |f|
    test[l] = {} unless test.has_key?(l)
    test[l][f] = {} unless test[l].has_key?(f)
  end
end

但是,由于您将值设置为散列,这是一个真实值。您还可以使用 ||= ,它仅在当前值为假时才分配一个值。 test[:non_existing_key] 将导致 nil(除非设置了默认值)。

表示以上可以替换为:

layers.each do |l|
  fillers.each do |f|
    test[l] ||= {}
    test[l][f] ||= {}
  end
end

您可以使用 product 来简化整个语句,它为您组合了两个循环。

layers.product(fillers) do |layer, filler|
  test[layer] ||= {}
  test[layer][filler] ||= {}
end