背景
我发现(尽管偶然)在用户定义的函数中使用!
方法(例如#sub!,#chomp!等)实际上可以改变对象传递的方式(即通过价值或参考)到该功能(或至少看起来如此)。
我知道!
方法用于就地修改对象,但老实说,我一直认为使用它们(或不使用它们)只是一个偏好问题。就我而言,我总是倾向于使用!
方法来获得稍微简短的语法(例如str.chomp!
而不是str = str.chomp
)。但是,在某些情况下,差异实际上可能是有害的。请允许我用以下示例解释。
示例:
下面的示例定义了两个函数change1
和change2
,它们将str
的值更改为“已更改!”分别使用#sub和#sub!方法。他们似乎做同样的事情,但请注意orig
的价值被change2
改变,但不是change1
改变。
我想我认为orig
在两种情况下都是通过值传递的,因此这两个函数的行为方式完全相同。但我错了。
# Pass by value
def change1(str)
str = str.sub(/^.*$/, 'CHANGED!') # Changes 'str' but not 'orig' (as expected)
return str
end
# Pass by reference...?
def change2(str)
str.sub!(/^.*$/, 'CHANGED!') # Changes 'str' AND 'orig' (unexpected!)
return str
end
orig = "original"
p change1(orig) #=> "CHANGED!"
p orig #=> "original"
p change2(orig) #=> "CHANGED!"
p orig #=> "CHANGED!"
问题:
如果对象是通过Ruby中的值传递的,那么使用!
方法如str.sub!(...)
如何改变一个甚至不在同一范围内的对象(看似通过引用传递它)? / p>
同样,为什么使用非!
方法(例如str = str.sub(...)
)会有不同的行为?
最重要的是,我怎么能知道这两种方法(貌似)会影响对象传递给我的函数的方式?例如,#sub!的文档仅声明它“就地执行与#sub相同的替换”。