用常量值初始化Ruby哈希

时间:2021-10-22 00:25:19

Actually I want to use such constructs in chef attributes, where I initialize a structure with a constant and modify it

实际上,我想在chef属性中使用这些构造,其中我用常量初始化一个结构并修改它

init_value = { "a" => { "b" => "c" } }
prepare = init_value
prepare["a"]["x"] = "y"

now init_value also contains ["a"]["x"] = "y", so when I prepare a new value

现在init_value也包含[a"]["x"] = "y",所以当我准备一个新值时

prepare = init_value
prepare["a"]["y"] = "x"

so prepare["a"] contains the keys ["b", "x", "y"].

所以准备[a]包含键(“b”、“x”、“y”)。

How can I initialize prepare with a constant without quoting the constant, so that in the last step, prepare["a"] only contains the two keys ["b","y"]?

如何在不引用常量的情况下用一个常量初始化prepare,以便在最后一步中,prepare["a"]只包含两个键["b","y"]?

3 个解决方案

#1


3  

You could move the initial hash into a method. This way, the method always 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"}}

#2


3  

Extracted from Rails 4.2.7

从Rails 4.2.7

  • Object#deep_dup "Returns a deep copy of object if it’s duplicable. If it’s not duplicable, returns self."

    如果对象是可复制的,则返回对象的深度副本。如果不能复制,返回self

  • Hash#deep_dup "Returns a deep copy of hash."

    哈希#deep_dup“返回一个深层的散列副本。”

  • Array#deep_dup "Returns a deep copy of array."

    数组#deep_dup“返回一个数组的深度拷贝。”

Implementation:

实现:

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

Then you could use a method for init_value so that deep_dup is always called and you can't accidentally forget

然后,您可以使用init_value的方法,以便始终调用deep_dup,并且您不会意外地忘记

#since you asked for a constant
INIT_VALUE = { "a" => { "b" => "c" } }.freeze

def init_value 
  INIT_VALUE.deep_dup 
end

And usage as such

和使用等

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"}}

#3


0  

I think you want a "deep copy" of init_value when assigning to prepare.

我认为在为prepare赋值时,您需要一个init_value的“深层副本”。

see: How do I copy a hash in Ruby?

看:如何在Ruby中复制散列?

#1


3  

You could move the initial hash into a method. This way, the method always 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"}}

#2


3  

Extracted from Rails 4.2.7

从Rails 4.2.7

  • Object#deep_dup "Returns a deep copy of object if it’s duplicable. If it’s not duplicable, returns self."

    如果对象是可复制的,则返回对象的深度副本。如果不能复制,返回self

  • Hash#deep_dup "Returns a deep copy of hash."

    哈希#deep_dup“返回一个深层的散列副本。”

  • Array#deep_dup "Returns a deep copy of array."

    数组#deep_dup“返回一个数组的深度拷贝。”

Implementation:

实现:

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

Then you could use a method for init_value so that deep_dup is always called and you can't accidentally forget

然后,您可以使用init_value的方法,以便始终调用deep_dup,并且您不会意外地忘记

#since you asked for a constant
INIT_VALUE = { "a" => { "b" => "c" } }.freeze

def init_value 
  INIT_VALUE.deep_dup 
end

And usage as such

和使用等

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"}}

#3


0  

I think you want a "deep copy" of init_value when assigning to prepare.

我认为在为prepare赋值时,您需要一个init_value的“深层副本”。

see: How do I copy a hash in Ruby?

看:如何在Ruby中复制散列?