问题是Ruby通过引用或值传递?吸引了很多有用的答案,也有很多不同意见.到目前为止,我在任何答案中都没有看到的是解释以下内容的任何内容:
ruby -e "def f(x) x=7 end; a=3; f(a); print a"
打印3.
ruby -e "def f(x) x[0]=7 end; a=[3]; f(a); print a[0]"
打印7.
根据经验,这看起来像标量对象和更复杂的对象(如散列和数组)之间存在某种区别,标量通过引用传递给值和复杂对象.这类似于C的语义.
我的理解是ruby中的所有东西都是一个对象,而早期问题的答案都没有提到标量和复杂类型之间的区别.那么我的描述是错误的,如果是,那么更好的描述是什么?
这里术语的问题是Ruby是"通过对象引用传递",这是一种在其他语言中使用"指向对象的指针"的方式.Ruby中指针和引用之间的界限是模糊的,因为没有实际的指针,加上对象本身通过引用计数保存在内存中,其中指针最终成为引用.所以它们是指向对象的指针,而不是传统意义上与同一个变量硬链接的引用.
根据定义,每个变量总是代表一个对象,即使它没有被定义:nil
它本身就是一个对象以及数字,甚至是浮点数.这使得术语"标量"几乎无关紧要,Ruby中没有基本类型,就像你在其他语言中一样,布尔值,数字,字符串和类实例之间的区别很大.
一般规则是您永远不能将变更反向传播到变量,但通过方法进行的更改确实会传播.要理解为什么,这里是Ruby看到你的代码的方式:
def f(x) # Change value of local variable x to 7 x = 7 end
这只是重新定义x
指向的对象,因为即使7是一个对象.
其他代码与Ruby的感知方式截然不同:
def f(x) # Send the []= method call to x with the argument 7 x.send(:[]=, 7) end
这会发送一条消息(方法调用)x
来触发该[]=
方法.该方法可以使用该值执行任何操作,但对于具有特定含义的数组,哈希和复数.它更新对象x
引用的内部状态.
您可以在其他场景中看到这种情况:
def f(x) x += 'y' end
这扩展到x = x + y
使用中间结果进行变量重新分配.原始x
值未修改.
def f(x) x << 'y' end
在这种情况下,x.send(:<<, 'y')
它会进行就地修改x
,因此原始版本会被修改.
在编写和理解Ruby代码时,能够识别方法调用是一件很重要的事情.有时它们甚至都不那么明显.你认为存在=
意味着"变量赋值",但事实并非如此:
def f(x) x.y = 'z' end
这看起来像是分配给y
属性,x
但它不是,它只是调用y=
方法,它相当于可以通过多种方式解释的x.send(:y=, 'z')
东西x
.这可能会修改价值,或者它可能会做一些完全不同的事情.没有x
更密切的了解就无法知道.