Rails コードベースを参照すると、options.dup への参照が多数見つかります。
def to_xml(options = {})
require 'builder' unless defined?(Builder)
options = options.dup
....
end
明らかに options.dup はオプション ハッシュを複製していますが、なぜこのコンテキストでこれを行う必要があるのでしょうか?
Rails コードベースを参照すると、options.dup への参照が多数見つかります。
def to_xml(options = {})
require 'builder' unless defined?(Builder)
options = options.dup
....
end
明らかに options.dup はオプション ハッシュを複製していますが、なぜこのコンテキストでこれを行う必要があるのでしょうか?
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
オブジェクトの浅いコピーを作成します。それはルビーコアのものです。Ruby では Hash や Array などのオブジェクトは参照渡しなので、関数内でオブジェクトを変更すると元のオブジェクトが変更されます。これが望ましい動作でない場合は、コピーを作成します...そのコードはそうします。
ruby-docを参照
アップデート
もう一つ。オブジェクトは参照によって渡されるため、新しく作成されたコピーへの参照options = options.dup
を変数に割り当てます。options
元のオブジェクトへの参照は 内で失われto_xml
ます。しかし、それはおそらくまだ呼び出すコードで参照されていますto_xml