Ruby是按值传递还是按引用传递?

Aru*_*run 4 ruby java oop pass-by-reference pass-by-value

我基本上是一个java开发人员.我在红宝石工作了大约一年.与java不同,Ruby是一种纯粹的面向对象的编程语言.这是一个疑问.它是按值传递还是按引用传递?Java作为pass-by-value工作:"当传递基元时,我看到该值被复制并传递给方法.但是如果有对象,则引用被复制并传递给方法.引用包含对象的位置在堆中.在方法调用期间,只传递对象的位置.因此不会创建重复的对象.同样的对象被修改."

但是当我尝试下面的ruby代码片段时,我得到了与Java相同的结果:"在方法调用期间,数字就像一个原语(比如在java中),而数组就像java中一样完美引用".现在,我很困惑.如果ruby中的所有内容都是对象,那么在方法调用期间为什么数字对象会重复?

class A
  def meth1(a)
    a = a+5
    puts "a inside meth1---#{a}"
  end

  def meth2(array)
    array.pop
    puts "array inside meth2---#{array}"
  end
end


obj1 = A.new
aa=5
obj1.meth1(aa)
puts "aa-----#{aa}"

arr = [3,4,5]
obj1.meth2(arr)
puts "arr---#{arr}"
Run Code Online (Sandbox Code Playgroud)

结果:

一个内部meth1 --- 10

AA ----- 5

数组里面的meth2 --- 34

ARR --- 34

Jör*_*tag 19

Ruby使用pass-by-value,或者更准确地说,是一个传递值的特殊情况,其中传递的值总是一个指针.这种特殊情况有时也称为共享呼叫,对象共享呼叫或逐个呼叫.

它与Java(对象),C#(默认情况下为引用类型),Smalltalk,Python,ECMAScript/JavaScript以及或多或少使用的每种面向对象语言使用的约定相同.

注意:在所有现有的Ruby实现上Symbol,Fixnums和Floats实际上是通过值直接传递的,而不是通过中间指针传递的.但是,由于这三个是不可变的,在这种情况下,传值和逐个对象共享之间没有可观察到的行为差异,因此您可以通过简单地将所有内容视为逐个调用来大大简化您的心理模型-sharing.只需将这三种特殊情况解释为内部编译器优化,您无需担心.

这是一个简单的例子,您可以运行以确定传递Ruby(或任何其他语言,在您翻译之后)的约定的参数:

def is_ruby_pass_by_value?(foo)
  foo.replace('More precisely, it is call-by-object-sharing!')
  foo = 'No, Ruby is pass-by-reference.'
  return nil
end

bar = 'Yes, of course, Ruby *is* pass-by-value!'

is_ruby_pass_by_value?(bar)

p bar
# 'More precisely, it is call-by-object-sharing!'
Run Code Online (Sandbox Code Playgroud)


Aru*_*hit 6

见下文,Object_id将回答您的所有问题:

class A
 def meth1(a)
  p a.object_id #=> 11
  a = a+5 # you passed a reference to the object `5`,but by `+` you created a new object `10`.
  p a.object_id #=> 21
 end

 def meth2(array)
  p array.object_id #=> 6919920
  array.pop
  p array.object_id #=> 6919920
 end
end


obj1 = A.new
aa=5
obj1.meth1(aa)
p aa.object_id #=> 11

arr = [3,4,5]
obj1.meth2(arr)
p arr.object_id #=> 6919920
Run Code Online (Sandbox Code Playgroud)

所以在你的代码中确实如此object reference is passed, by value.注意+创建一个新对象,因此引用是10在本地进行更改的方法.


T.J*_*der 6

它在两种情况下都是传值,比如Java.不同之处在于测试中的两个项都是对象,而在Java中,一个是原始的,另一个是对象.但无论某种东西是原始的还是对象,都没有影响传值和传递参考.按值传递与传递引用有关,被调用的方法可以对传递给它的调用上下文中的变量执行什么操作.

让我们忽略语言和对象,只看看传值与传递实际意味着什么.我将在模糊的B/Java/C/C++/C#/ D语法中使用伪代码:

Function Foo(arg) {
  arg = 6
}

declare variable a
a = 5
Foo(a)
output a
Run Code Online (Sandbox Code Playgroud)

如果a是按值传递,输出是5,如果a通过引用传递(一个参考给变量a被给予Foo)时,输出为6,因为Foo正在a经由到变量的引用.

请注意,您的两个测试之间存在很大差异.

在第一次测试中,您将为以下内容分配一个全新的值a:

a = a + 5
Run Code Online (Sandbox Code Playgroud)

您没有修改a传入方法的版本,而是使用该值为其分配a.

在第二次测试中,您只需修改array:

array.pop
Run Code Online (Sandbox Code Playgroud)

不是,例如:

array = ...put something entirely new in `array`...
Run Code Online (Sandbox Code Playgroud)

在您的测试中,由于您只是修改了对象引用所指向的内容,而不是更改引用,当然您会看到该修改.但是如果您实际上已经分配了一个新数组array,那么在调用上下文中这种更改就不会显而易见了.