浏览 Rails 代码库,我发现许多对 options.dup 的引用。
def to_xml(options = {})
require 'builder' unless defined?(Builder)
options = options.dup
....
end
显然 options.dup 是在复制 options 哈希,但你为什么要在这种情况下这样做呢?
浏览 Rails 代码库,我发现许多对 options.dup 的引用。
def to_xml(options = {})
require 'builder' unless defined?(Builder)
options = options.dup
....
end
显然 options.dup 是在复制 options 哈希,但你为什么要在这种情况下这样做呢?
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
。这是遵循最小惊讶原则的常见模式。在 Ruby 中,修改其参数的方法通常以!
后缀命名,以提醒用户它们是破坏性/修改操作。dup
应该调用该方法的非版本replace_two!
来指示这种副作用。
dup
创建对象的浅表副本。这是红宝石核心的东西。由于像 Hash 和 Array 这样的 ruby 对象是通过引用传递的,因此当您在函数内部更改对象时,这将更改原始对象。如果这不是所需的行为 - 您创建一个副本......那么代码就可以了。
更新
还有一件事。由于对象是通过引用传递的,options = options.dup
因此将分配给options
新创建的副本的变量引用。对原始对象的引用在内部丢失to_xml
。但它仍然可能在调用的代码中被引用to_xml