Работа Ruby - это комбинация передачи по значению и передачи по ссылке.Фактически, Ruby использует передачу по значению со ссылками.
Вы можете прочитать больше в следующих темах:
Некоторые заметные цитаты:
Абсолютно верно: Ruby использует передачу по значению - со ссылками.
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"
Строка является распространенным случаем, когда большая часть операций работает с клонами, а не с экземпляром self.По этой причине у нескольких методов есть версия взрыва, которая выполняет одну и ту же операцию на месте.
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