【问题标题】:Freezing HashWithIndifferentAccess in Ruby在 Ruby 中冻结 HashWithIndifferentAccess
【发布时间】:2021-01-09 03:06:42
【问题描述】:

我试图在 Ruby 中冻结嵌套的 HashWithIndifferentAccess 并遇到了一些意外行为。如果不使用.with_indifferent_access 包装内部或外部哈希,它可以按预期工作:

v = { 'a' => { 'b' => 2 }.freeze }.freeze
v['a'].frozen? => true

v_1[:a]v_2[:a] 都是 HashWithIndifferentAccess 的,但只有 v_1[:a] 被冻结。这是为什么呢?

v_1 = { 'a' => { 'b' => 2 }.with_indifferent_access.freeze }.with_indifferent_access.freeze
v_1[:a].frozen? => true
v_2 = { 'a' => { 'b' => 2 }.freeze }.with_indifferent_access.freeze
v_2[:a].frozen? => false

提前致谢!

【问题讨论】:

    标签: ruby-on-rails ruby activesupport


    【解决方案1】:

    所以我们正在研究嵌套哈希的行为如何不同

    v_1 = { a: { b: 2 } }.with_indifferent_access
    v_2 = { a: { b: 2 }.with_indifferent_access }.with_indifferent_access
    

    当你调用Hash#with_indifferent_access时,它会创建一个新的ActiveSupport::HashWithIndifferentAccess对象;然后调用#update 将原始哈希中的所有键/值对插入到新对象(ActiveSupport::HashWithIndifferentAccess#update)中,该对象使用嵌套哈希调用#convert_values

    def convert_value(value, options = {})
      if value.is_a? Hash
        if options[:for] == :to_hash
          value.to_hash
        else
          value.nested_under_indifferent_access
        end
        ...
    

    所以{ b: 2 }{ b: 2 }.with_indifferent_access 都会调用#nested_under_indifferent_access。但这对于 Hash 来说是一种不同于 HashWithIndifferentAccess 的方法。在core_ext文件中,Hash#nested_under_indifferent_access调用HashWithIndifferentAccess.new(self),但HashWithIndifferentAccess#nested_under_indifferent_access只返回self

    所以{'b' => 2}.nested_under_indifferent_access 返回一个新对象,但{'b' => 2}.with_indifferent_access.nested_under_indifferent_access 不对该对象做任何事情。这就是为什么如果第一个被冻结,你会得到一个不同的(默认未冻结)对象,如果第二个被冻结,它会保持冻结状态。

    【讨论】:

      【解决方案2】:

      如果您查看implementation details 中的with_indifferent_access,您会发现它实际上是原始哈希的dupdup-ed 哈希不会被冻结。通过在返回的哈希(来自with_indifferent_access)上调用freeze,您可以冻结它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-10-23
        • 2015-10-31
        • 2013-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多