做!方法会影响对象传递给函数的方式吗?

时间:2014-12-31 00:17:41

标签: ruby scope pass-by-reference pass-by-value in-place

背景

我发现(尽管偶然)在用户定义的函数中使用!方法(例如#sub!#chomp!等)实际上可以改变对象传递的方式(即通过价值或参考)到该功能(或至少看起来如此)。

我知道!方法用于就地修改对象,但老实说,我一直认为使用它们(或不使用它们)只是一个偏好问题。就我而言,我总是倾向于使用!方法来获得稍微简短的语法(例如str.chomp!而不是str = str.chomp)。但是,在某些情况下,差异实际上可能是有害的。请允许我用以下示例解释。

示例:

下面的示例定义了两个函数change1change2,它们将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相同的替换”。

0 个答案:

没有答案