2013-05-09 3 views
4

Я в основном разработчик Java. Я работаю в рубине около года. В отличие от java, Ruby - это чисто объектно-ориентированный язык программирования. Здесь возникает сомнение. Является ли это передачей по значению или передачей по ссылке? Java работает как pass-by-value: «При передаче примитивов я вижу, что значение дублируется и передается методу.Но incase of Objects, ссылка дублируется и передается методу. Ссылка содержит местоположение объекта в куче. Во время вызова метода передается только местоположение объекта, поэтому не создается повторяющихся объектов. Один и тот же объект модифицируется ».Является ли Ruby pass-by-value или pass-by-reference?

Но когда я попробовал фрагмент кода ниже, я получил те же результаты, что и на 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}" 

Результаты:

внутри meth1 --- 10

аа ----- 5

массив внутри meth2 --- 34

обр --- 34

+0

дублировать [здесь] (http://stackoverflow.com/ q/22827566/995714) и [здесь] (http://stackoverflow.com/q/1872110/995714) –

ответ

17

Ruby использует pass-by-value, или, точнее, специальный случай pass-by-value, где переданное значение равно всегда указатель. Этот специальный случай также иногда называют совместным использованием вызовов, совместным использованием вызовов по вызову или позором.

Это то же самое соглашение, которое используется Java (для объектов), C# (по умолчанию для ссылочных типов), Smalltalk, Python, ECMAScript/JavaScript и более или менее каждый объектно-ориентированный язык, когда-либо созданный.

Примечания: на все существующие реализациях Ruby, Symbol s, Fixnum s и s Float фактически передаются непосредственно по значению и не с посредническим указателем. Тем не менее, поскольку эти три являются неизменными, в этом случае не наблюдается наблюдаемой поведенческой разницы между передачей по значению и совместным использованием вызова по объектам, поэтому вы можете значительно упростить свою ментальную модель, просто обращаясь все как звонок -объект обмена. Просто интерпретируйте эти три специальных случая как внутреннюю оптимизацию компилятора, о которой вам не нужно беспокоиться.

Вот простой пример, который вы можете запустить, чтобы определить аргумент прохождения конвенции Руби (или любой другой язык, после перевода его):

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!' 
+1

'на всех существующих реализациях Ruby. Символы, Fixnums и Floats фактически передаются непосредственно по значению, а не с помощью указателя-посредника.« Мне очень понравилось, я думал, будет включать. Но вы сделали это, кажется, хорошо. :) Но я думаю, что вы также должны включить в свой список 'true',' nil' и 'false'. –

+0

Чтобы продолжить движение по нему домой, добавьте строку после foo = 'No .... say "foo.relpace (' some text ')" –

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 

Так что это правда, что в вашем коде object reference is passed, by value. Примечание + создайте новый объект, таким образом, ссылка на 10 сделана локально для метода, где он был изменен.

+0

Awesome !!! Ты гений. Спасибо за ваш подробный ответ :) – Arun

6

Это пропускная способность в обоих случаях, например Java. Разница в том, что оба элемента в ваших тестах являются объектами, тогда как в Java один из них был бы примитивным, а другой - объектом. Но является ли что-то примитивным или объект не имеет отношения к прохождению по сравнению с передачей по ссылке. Передача по значению по сравнению с передачей по ссылке связана с тем, что вызываемый метод может сделать с переменными в , вызывающем контекст, который передается в него.

Давайте проигнорируем как языки, так и объекты, и просто посмотрим, что означает значение pass-by-value или pass-by-reference. Я буду использовать псевдо-код в синтаксисе неопределенно В/Java/C/C++/C#/D:

Function Foo(arg) { 
    arg = 6 
} 

declare variable a 
a = 5 
Foo(a) 
output a 

Если a передается по значению, выход 5. Если a передается по ссылке (а ссылка на переменную a дана Foo), выход 6, потому что Foo работает с a через ссылку на переменную.

Обратите внимание, что между двумя вашими испытаниями существует существенная разница.

В своем первом тесте, вы присваиваете совершенно новое значение a:

a = a + 5 

Вы не модификации версии a передается в метод, вы используете это значение присвойте значение a.

В вашем втором тесте, вы просто модифицируя array:

array.pop 

Не, например:

array = ...put something entirely new in `array`... 

В тесте, так как вы просто изменяя вещь, что объект контрольные точки, а не изменение ссылки, конечно, вы видите эту модификацию. Но если бы вы присвоили новый массив array, это изменение не было бы очевидно в вызывающем контексте.

+0

Спасибо за ваш ответ :) – Arun

+0

«что оба элемента в ваших тестах - объекты» На самом деле это обе ссылки. «Объекты» не являются значениями в Java или Ruby – newacct

+0

@newacct: Нет, оба элемента в тесте являются объектами (числовым объектом и объектом массива). И да, когда они передаются в функцию, то, что передается, является ссылкой на этот объект (а не сам объект), как это совершенно ясно из вышеизложенного. Тест - это все, а не только узкий бит, где ссылка на объект передается в функцию. –

4

Ruby, как Java, является передачей по значению ... С уловкой: переданное «значение» (в случае объектов) ссылка на указатель, поэтому должна быть сделана любая модификация значения объекта внутри метода он будет на том же объекте, что и в вызывающем контексте.

Теперь, к вашим примерам, вы должны знать, что FixNum являются «немедленными» объектами, которые имеют только значение - ссылка в этом случае не указатель, а сам объект (он все еще является объектом, с методами, и т. д., поэтому это не примитив, как в Java).

В вашем примере, вы на самом деле переназначение нового объекта на свой «а» указатель, который во всех случаях не может быть отражен в любом месте, так же, как:

my_name = "John" 
my_name = "Robert" 

фактически назначая новый указатель к ссылке. Поскольку нет способа изменить значение FixNum в Ruby, это не тот случай, который может работать.

Ситуация с массивом - это то, что вы, вероятно, ожидаете: у вас есть объект, вы делаете модификацию состояния объекта и возвращаете измененное состояние.

Смежные вопросы