用常量值初始化 Ruby hash
Initialize Ruby hash with a constant value
实际上我想在 chef 属性中使用这样的构造,我在其中用常量初始化一个结构并修改它
init_value = { "a" => { "b" => "c" } }
prepare = init_value
prepare["a"]["x"] = "y"
现在init_value也包含["a"]["x"] = "y"
,所以当我准备一个新值
prepare = init_value
prepare["a"]["y"] = "x"
所以 prepare["a"]
包含键 ["b", "x", "y"]
.
如何在不引用常量的情况下使用常量初始化准备,以便在最后一步中,prepare["a"]
仅包含两个键 ["b","y"]
?
我想你在分配准备时想要 "deep copy" 的 init_value。
见:
How do I copy a hash in Ruby?
摘自Rails 4.2.7
Object#deep_dup
"Returns a deep copy of object if it’s duplicable. If it’s not duplicable, returns self."
Hash#deep_dup
"Returns a deep copy of hash."
Array#deep_dup
"Returns a deep copy of array."
实施:
class Object
def duplicable?
true
end
def deep_dup
duplicable? ? dup : self
end
end
class Hash
def deep_dup
each_with_object(dup) do |(key, value), hash|
hash[key.deep_dup] = value.deep_dup
end
end
end
class Array
def deep_dup
map { |it| it.deep_dup }
end
end
# Not duplicable?
# if ruby version < 2.0 also add Class and Module as they were not duplicable until 2.0
[Method, Symbol, FalseClass, TrueClass, NilClass, Numeric, BigDecimal].each do |m|
m.send(:define_method, :duplicable?, ->{false})
end
然后你可以为 init_value
使用一个方法,这样 deep_dup
总是被调用,你就不会不小心忘记
#since you asked for a constant
INIT_VALUE = { "a" => { "b" => "c" } }.freeze
def init_value
INIT_VALUE.deep_dup
end
这样的用法
prepare = init_value
prepare["a"]["x"] = "y"
prepare2 = init_value
prepare2["a"]["y"] = "x"
prepare
#=> {"a"=>{"b"=>"c", "x"=>"y"}}
prepare2
#=> {"a"=>{"b"=>"c", "y"=>"x"}}
您可以将初始哈希移动到一个方法中。这样,该方法总是 returns a "fresh" hash:
def init_value
{"a"=>{"b"=>"c"}}
end
prepare = init_value
prepare["a"]["x"] = "y"
prepare
#=> {"a"=>{"b"=>"c", "x"=>"y"}}
prepare = init_value
prepare["a"]["y"] = "x"
prepare
#=> {"a"=>{"b"=>"c", "y"=>"x"}}
实际上我想在 chef 属性中使用这样的构造,我在其中用常量初始化一个结构并修改它
init_value = { "a" => { "b" => "c" } }
prepare = init_value
prepare["a"]["x"] = "y"
现在init_value也包含["a"]["x"] = "y"
,所以当我准备一个新值
prepare = init_value
prepare["a"]["y"] = "x"
所以 prepare["a"]
包含键 ["b", "x", "y"]
.
如何在不引用常量的情况下使用常量初始化准备,以便在最后一步中,prepare["a"]
仅包含两个键 ["b","y"]
?
我想你在分配准备时想要 "deep copy" 的 init_value。
见: How do I copy a hash in Ruby?
摘自Rails 4.2.7
Object#deep_dup
"Returns a deep copy of object if it’s duplicable. If it’s not duplicable, returns self."Hash#deep_dup
"Returns a deep copy of hash."Array#deep_dup
"Returns a deep copy of array."
实施:
class Object
def duplicable?
true
end
def deep_dup
duplicable? ? dup : self
end
end
class Hash
def deep_dup
each_with_object(dup) do |(key, value), hash|
hash[key.deep_dup] = value.deep_dup
end
end
end
class Array
def deep_dup
map { |it| it.deep_dup }
end
end
# Not duplicable?
# if ruby version < 2.0 also add Class and Module as they were not duplicable until 2.0
[Method, Symbol, FalseClass, TrueClass, NilClass, Numeric, BigDecimal].each do |m|
m.send(:define_method, :duplicable?, ->{false})
end
然后你可以为 init_value
使用一个方法,这样 deep_dup
总是被调用,你就不会不小心忘记
#since you asked for a constant
INIT_VALUE = { "a" => { "b" => "c" } }.freeze
def init_value
INIT_VALUE.deep_dup
end
这样的用法
prepare = init_value
prepare["a"]["x"] = "y"
prepare2 = init_value
prepare2["a"]["y"] = "x"
prepare
#=> {"a"=>{"b"=>"c", "x"=>"y"}}
prepare2
#=> {"a"=>{"b"=>"c", "y"=>"x"}}
您可以将初始哈希移动到一个方法中。这样,该方法总是 returns a "fresh" hash:
def init_value
{"a"=>{"b"=>"c"}}
end
prepare = init_value
prepare["a"]["x"] = "y"
prepare
#=> {"a"=>{"b"=>"c", "x"=>"y"}}
prepare = init_value
prepare["a"]["y"] = "x"
prepare
#=> {"a"=>{"b"=>"c", "y"=>"x"}}