赋值和参数传递
大多数情况下,Ruby 方法有两个接入点 - 比如进出房间的门。参数列表提供了入口;返回值提供了出口。对输入参数的修改不会影响原始数据,原因很简单,当 Ruby 计算表达式时,该计算结果会创建一个新对象 - 因此对参数所做的任何更改只会影响新对象,而不会影响原始对象数据。但是这个规则有例外,我们稍后会看到这样的示例。
让我们从最简单的情况开始:一个方法,它将获取一个值,其作为命名参数,并返回另一个值:
def change( x )
x += 1
return x
end
从表面上看,你可能会认为我们正在处理单个对象 x
,这里:对象 x
进入 change
方法并返回同一个对象 x
。事实上,情况并非如此。一个对象进入(参数),出来的是一个不同的对象(返回值)。你可以轻松验证这一点,使用 object_id
方法以显示程序中每个对象的唯一标识数字:
num = 10
puts( "num.object_id=#{num.object_id}" )
num = change( num )
puts( "num.object_id=#{num.object_id}" )
在调用 change
方法之前和之后,变量 num
的标识符是不同的。这表明,即使变量名保持不变,change
方法返回的 num
对象也不同于发送给它的 num
对象。
方法调用本身与对象的更改无关。你可以通过运行 method_call.rb 来验证这一点。这只是将 num
对象传递给 change
方法并返回它:
def nochange( x )
return x
end
在这种情况下,返回之后的 num
与发送到方法之前的 num
的 object_id
相同。换句话说,进入方法的对象与再次出来的对象完全相同。这产生了一个必然的结论,即在 change
方法(x += 1
)中有一些关于赋值(assignment)的行为导致创建了新的对象。
但是赋值行为本身并不能解释这个问题。如果只是为自己分配一个变量,则不会创建新对象…
num = 10
num = num # a new num object is not created
那么,如果你为对象分配的值与已有的值相同怎么办?
num = 10
num = 10 # a new num object is not created
这表明单独的赋值必定不会创建新的对象。现在让我们尝试分配一个新值…
num = 10
num += 1 # this time a new num object is created
通过查看 object_id
,我们可以确定当为现有的变量分配新值时,会创建一个新对象。
大多数数据项被视为是唯一的,因此一个字符串,”hello” 被认为与其它另一个字符串 “hello” 不同,以及一个浮点数 10.5 被认为与其它另一个浮点数 10.5 不同。因此,任何字符串(string)或浮点数(float)赋值操作都将创建一个新对象。
但是在处理整数(integer)时,只有当分配的值与前一个值不同时才会创建一个新对象。你可以在赋值运算符的右侧执行各种复杂的操作,但如果生成的值与原始值相同,则不会创建新对象…
num = (((num + 1 - 1) * 100) / 100) # a new object is not created!