浏览 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