【问题标题】:Clone constant of hash into new variable without mutating constant on update with .each block?将散列常量克隆到新变量中而不用.each块更新常量?
【发布时间】:2018-05-03 16:05:59
【问题描述】:

我正在为某事苦苦挣扎。我已将我的代码抽象为尽可能简单,但我仍然不明白它为什么会有这种行为。

我正在创建一个由一组键值对组成的常量并将其冻结。然后我使用 .dup 方法将散列复制到一个新变量中。

但是,当我遍历一个数组并尝试将其存储在新变量的(以前为空的)数组中时,它不仅会更新新变量,还会更新原始常量。这似乎只适用于 .each 方法 - 如果我直接将新值作为新数组传递,它可以在不更新常量的情况下工作。

我的抽象代码如下:

CONFIG_VALUES = { results: [], loop_count: 0 }.freeze
the_results = ["foo", "bar"]
abc = CONFIG_VALUES.dup
the_results.each do |res| 
  abc[:results] << res
end
abc
#=> {:results=>["foo", "bar"], :loop_count=>0}
CONFIG_VALUES
#=> {:results=>["foo", "bar"], :loop_count=>0}

【问题讨论】:

    标签: ruby-on-rails ruby constants immutability ruby-hash


    【解决方案1】:

    Hash#dup 方法不是递归的。无论如何,如果你使用 Ruby on Rails,并且我认为你已经标记了它,你可以使用 #deep_dup 方法:http://api.rubyonrails.org/classes/Hash.html#method-i-deep_dup

    这是一个 ActiveSupport 方法,所以你可以只使用 gem 以防你不使用 Ruby on Rails。

    【讨论】:

    • 啊哈!这解释了它并修复它。非常感谢 :) 我会进一步阅读 deep_dup 方法。
    • :) 很高兴为您提供帮助!
    【解决方案2】:

    您可以通过以下方式达到预期的效果:

    CONFIG_VALUES = { results: [], loop_count: 0 }.freeze
    the_results = %w[foo bar]
    
    abc = CONFIG_VALUES.merge(results: the_results)
    
    abc
    #=> {:results=>["foo", "bar"], :loop_count=>0}
    CONFIG_VALUES
    #=> {:results=>[], :loop_count=>0}
    

    据我了解,这是有效的,因为 #merge 不会改变 CONFIG_VALUES 并且您实际上是在创建一组全新的对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      • 2019-05-27
      • 1970-01-01
      • 1970-01-01
      • 2017-02-16
      • 1970-01-01
      • 2018-05-15
      相关资源
      最近更新 更多