Ответ 1
Способ Ruby - это комбинация прохода по значению и передача по ссылке. Фактически, Ruby использует pass по значению со ссылками.
Вы можете прочитать больше в следующих разделах:
Некоторые заметные цитаты:
Абсолютно верно: Ruby использует pass by value - со ссылками.
irb(main):004:0> def foo(x) x = 10 end => nil irb(main):005:0> def bar; x = 20; foo(x); x end => nil irb(main):006:0> bar => 20 irb(main):007:0>
Нет стандартного способа (т.е. кроме привлечения eval и метапрограммирование магии), чтобы сделать переменную в области вызова другой объект. И, кстати, это не зависит от объекта, переменная относится к. Непосредственные объекты в Ruby легко интегрируются с остальные (например, POD в Java) и Ruby языковой перспективы вы не видите никакой разницы (кроме возможно, производительность). Это одна из причин, почему Ruby настолько изящна.
и
Когда вы передаете аргумент в метод, вы передаете переменная, указывающая на ссылку. В некотором смысле, это комбинация пройти по значению и пройти по ссылке. Я имею в виду, вы передаете значение переменной в методе, однако значение переменная всегда является ссылкой на объект.
Разница между:
def my_method( a ) a.gsub!( /foo/, 'ruby' ) end str = 'foo is awesome' my_method( str ) #=> 'ruby is awesome' str #=> 'ruby is awesome'
и
def your_method( a ) a = a.gsub( /foo/, 'ruby' ) end str = 'foo is awesome' my_method( str ) #=> 'ruby is awesome' str #=> 'foo is awesome'
заключается в том, что в #my_method вы вызываете #gsub! который изменяет объект (а) на месте. Поскольку переменная 'str' (вне области метода) и переменная "a" (внутри области метода) имеет "значение", которое ссылка на тот же объект, отражение на этом объекте отражается в переменной "str" после вызова метода. В #your_method вы вызовите #gsub, который не изменяет исходный объект. Вместо этого создает новый экземпляр String, содержащий модификации. когда вы назначаете этот объект переменной 'a', вы меняете значение из 'a', чтобы быть ссылкой на этот новый экземпляр String. Однако значение 'str' все еще содержит ссылку на оригинальную (немодифицированную) Строковый объект.
Является ли метод изменением ссылки или ссылочного объекта зависит от типа класса и реализации метода.
string = "hello"
def changer(str)
str = "hi"
end
changer(string)
puts string
# => "hello"
string
не изменяется, поскольку присвоение строк заменяет ссылку, а не ссылочное значение.
Я хочу изменить строку на месте, вам нужно использовать String#replace
.
string = "hello"
def changer(str)
str.replace "hi"
end
changer(string)
puts string
# => "hi"
String - обычный случай, когда большая часть операций работает на клонах, а не на экземпляре self. По этой причине несколько методов имеют версию bang, которая выполняет ту же самую операцию.
str1 = "hello"
str2 = "hello"
str1.gsub("h", "H")
str2.gsub!("h", "H")
puts str1
# => "hello"
puts str2
# => "Hello"
Наконец, чтобы ответить на ваш оригинальный вопрос, вы не можете изменить строку. Вы можете назначить ему новое значение или перенести строку в другой изменяемый объект и заменить внутреннюю ссылку.
$wrapper = Struct.new(:string).new
$wrapper.string = "String"
def changer(w)
w.string = 1
end
changer($wrapper)
puts $wrapper.string
# => 1