在 Ruby 中冻结 HashWithIndifferentAccess
Freezing HashWithIndifferentAccess in Ruby
我试图冻结 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
提前致谢!
如果您查看 with_indifferent_access
的 implementation details,您会发现它实际上是原始哈希的 dup
。 dup
-ed 哈希未被冻结。通过在返回的散列(来自 with_indifferent_access
)上调用 freeze
,你冻结它。
所以我们正在研究嵌套散列在
之间的行为有何不同
v_1 = { a: { b: 2 } }.with_indifferent_access
v_2 = { a: { b: 2 }.with_indifferent_access }.with_indifferent_access
当您调用 Hash#with_indifferent_access, it creates a new ActiveSupport::HashWithIndifferentAccess
object; and then calls #update
to insert all of the key/value pairs from the original hash into the new object (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
只是 returns self
.
所以{'b' => 2}.nested_under_indifferent_access
returns一个新的对象,但是{'b' => 2}.with_indifferent_access.nested_under_indifferent_access
不对对象做任何事情。这就是为什么如果第一个被冻结,你会得到一个不同的(默认情况下未冻结)对象,如果第二个被冻结,它会保持冻结状态。
我试图冻结 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
提前致谢!
如果您查看 with_indifferent_access
的 implementation details,您会发现它实际上是原始哈希的 dup
。 dup
-ed 哈希未被冻结。通过在返回的散列(来自 with_indifferent_access
)上调用 freeze
,你冻结它。
所以我们正在研究嵌套散列在
之间的行为有何不同v_1 = { a: { b: 2 } }.with_indifferent_access
v_2 = { a: { b: 2 }.with_indifferent_access }.with_indifferent_access
当您调用 Hash#with_indifferent_access, it creates a new ActiveSupport::HashWithIndifferentAccess
object; and then calls #update
to insert all of the key/value pairs from the original hash into the new object (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
只是 returns self
.
所以{'b' => 2}.nested_under_indifferent_access
returns一个新的对象,但是{'b' => 2}.with_indifferent_access.nested_under_indifferent_access
不对对象做任何事情。这就是为什么如果第一个被冻结,你会得到一个不同的(默认情况下未冻结)对象,如果第二个被冻结,它会保持冻结状态。