2

实际上我想在厨师属性中使用这样的结构,我用一个常量初始化一个结构并修改它

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

4

3 回答 3

3

从 Rails 4.2.7 中提取

  • Object#deep_dup “如果它是可复制的,则返回对象的深层副本。如果它不可复制,则返回自我。”

  • Hash#deep_dup “返回哈希的深层副本。”

  • Array#deep_dup “返回数组的深层副本。”

执行:

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"}}
于 2017-05-23T16:31:29.470 回答
3

您可以将初始哈希移动到方法中。这样,该方法总是返回一个“新鲜”的哈希:

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"}}
于 2017-05-23T19:17:05.510 回答
0

我认为您在分配准备时需要 init_value 的“深层副本”。

请参阅: 如何在 Ruby 中复制哈希?

于 2017-05-23T15:56:49.480 回答