更改ruby变量/引用的值

我偶然发现了一些我不太了解的事情。 我知道ruby中的变量是引用。 所以很棒的东西是可能的。 但是当我将变量传递给方法时,它表现得很奇怪:

my_var_a = "nothing happend to me" my_var_b = "nothing happend to me" def parse_set(my_var_set) my_var_set = "my value changed" end def parse_sub(my_var_sub) my_var_sub.sub! /(.*)/, "my value changed" end parse_set(my_var_a) parse_sub(my_var_b) my_var_a # => "nothing happend to me" my_var_b # => "my value changed" 

你能解释一下为什么它适用于sub!=保持对象不变? 我怎么能避免使用sub! 但结果相同?

my_var_amy_var_set是不同的引用,但它们指向同一个对象。 如果修改my_var_set的对象,则更改将显示在my_var_a 。 但是,如果您在新对象上重新指定my_var_set ,则不会更改my_var_a指向的内容。

编辑:澄清……

Ruby所做的是通过值传递引用。 当你说

 my_var_a = "nothing happend to me" 

Ruby在内存位置保存字符串“没有任何事情发生在我身上”(让我们称之为1000),并将my_var_a引用保存在另一个内存位置(比方说2000)。 当您的代码使用my_var_a ,解释器会查看位置2000,看它指向1000,然后从1000获取实际的字符串值。

当你调用parse_set(my_var_a) ,Ruby实际上会创建一个名为my_var_set的新引用, my_var_a其指向my_var_a指向的字符串(内存位置1000)。 但是, my_var_setmy_var_a引用的副本 – 假设my_var_set是在内存位置3000创建的my_var_amy_var_set是内存中2个完全不同的引用,它们恰好指向保存字符串值的同一个精确内存位置。

my_var_set = "my value changed"的语句my_var_set = "my value changed"parse_set创建一个新字符串,并将my_var_set指向该新内存位置。 但是,这不会改变原始my_var_a参考指向的内容! 既然my_var_set指向不同的内存位置,那么您对该变量所做的任何操作都不会影响my_var_a

对于parse_sub也会发生相同的引用副本。 但是parse_sub更改字符串的原因是因为您直接在my_var_sub引用上调用方法。 执行此操作时,解释器将获取my_var_sub指向的对象,然后对其进行修改。 因此,更改将显示在my_var_a引用中,因为它仍指向相同的字符串。

 irb(main):008:0* a = 'abc' => "abc" irb(main):009:0> a.replace('def') => "def" irb(main):010:0> a => "def" 

在我用Ruby编程的这些年里,我不得不使用replace完全零次。 我想知道你的代码是否有更好的设计。

更改接收器的大多数字符串方法都带有后缀! (sub!,大写!,chomp!等)有些更改接收器的内容不是后缀! (替换是一个)。 如果调用更改接收器的方法,则对该对象的任何和所有引用都将看到更改。 如果调用不更改接收器的方法,则该方法返回一个新字符串

gsub不会修改接收器,而是返回一个新的String实例:

 a = "foo" b = a p a.sub(/o/, '#') # "f##" pa # => "foo" pb # => "foo" 

GSUB! 修改接收器:

 a = "foo" b = a p a.sub!(/o/, '#') # => "f#o" pa # => "f#o" pb # => "f#o" 

“我怎样才能避免使用sub!但结果相同?”

 def parse_set() "my value changed" end a = parse_set() 

将它设置为对象的实例变量(虽然这只适用于您的主脚本,但如果您想使用实例变量方法,我建议您创建自己的类)。

 @my_var_a = "nothing happend to me" def parse_set() @my_var_a = "my value changed" end