浏览Rails代码库我发现了很多对options.dup的引用。
def to_xml(options = {})
require 'builder' unless defined?(Builder)
options = options.dup
....
end
显然,options.dup正在复制选项哈希,但为什么你希望在这种情况下这样做呢?
答案 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