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

Geo*_*rgi 3 ruby ruby-on-rails

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

def to_xml(options = {})
  require 'builder' unless defined?(Builder)
  options = options.dup
  ....
end
Run Code Online (Sandbox Code Playgroud)

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

Jim*_*art 7

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

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

options = { one: "foo", two: "bar" }
replace_two(options)
puts options[:two]
Run Code Online (Sandbox Code Playgroud)

这将打印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]
Run Code Online (Sandbox Code Playgroud)

会打印bar.这是遵循最小惊讶原则的常见模式.在Ruby中,修改其参数的方法通常以!后缀命名,以警告用户它们是破坏性/修改操作.dup应调用该方法的非版本replace_two!以指示此副作用.


den*_*-bu 5

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

请参阅ruby-doc

UPDATE

还有一件事.由于对象是通过引用传递的,因此options = options.dup将赋予options对新创建的副本的变量引用.内部对原始对象的引用丢失了to_xml.但它仍然可能在调用的代码中引用to_xml