Ruby on Rails中options.dup的目的是什么?

时间:2013-03-28 12:14:03

标签: ruby-on-rails ruby

浏览Rails代码库我发现了很多对options.dup的引用。

def to_xml(options = {})
  require 'builder' unless defined?(Builder)
  options = options.dup
  ....
end

显然,options.dup正在复制选项哈希,但为什么你希望在这种情况下这样做呢?

2 个答案:

答案 0 :(得分:7)

dup克隆一个对象。将对象传递给方法时,任何更改该对象内部状态的内容都将反映在调用范围中。例如,尝试以下代码:

def replace_two(options)
  options[:two] = "hi there"
end

options = { one: "foo", two: "bar" }
replace_two(options)
puts options[:two]

这将打印hi there,因为replace_two()修改了哈希内容。

如果您想避免更改传入的options,可以在其上调用.dup,然后对克隆所做的任何更改都不会反映在调用范围中:

def replace_two(options)
  options = options.dup
  options[:two] = "hi there"
end

options = { one: "foo", two: "bar" }
replace_two(options)
puts options[:two]

将打印bar。这是Principle of Least Astonishment之后的常见模式。在Ruby中,修改其参数的方法通常以!后缀命名,以提醒用户它们是破坏性/修改操作。该方法的非dup版本应该被称为replace_two!,以表明这种副作用。

答案 1 :(得分:5)

dup创建对象的浅表副本。这是红宝石的核心东西。因为像Hash和Array这样的ruby对象是通过引用传递的,所以当你更改一个函数内部的对象时,这将改变原始对象。如果这不是所希望的行为 - 你创建一个副本......所以代码确实如此。

请参阅ruby-doc

<强>更新

还有一件事。由于对象是通过引用传递的,options = options.dup将为新创建的副本分配options变量引用。在to_xml内丢失了对原始对象的引用。但它仍然可能在调用to_xml

的代码中引用