更改ruby变量/引用的值

更改ruby变量/引用的值,ruby,variables,reference,scope,Ruby,Variables,Reference,Scope,我只是偶然发现了一些我不太明白的东西。我知道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.s

我只是偶然发现了一些我不太明白的东西。我知道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\u var\u a
my\u var\u set
是不同的引用,但它们指向相同的对象。如果在
my\u var\u集合
中修改对象,更改将显示在
my\u var\u a
中。但是,如果将
my\u var\u set
重新指向一个新对象,则不会更改
my\u var\u a
指向的对象

def parse_set()
  "my value changed"
end

a = parse_set()
编辑:澄清

Ruby所做的就是按值传递引用。当你说

my_var_a = "nothing happend to me"
Ruby将字符串“nothing happend to me”保存在一个内存位置(我们称之为1000),并将
my\u var\u a
引用保存在另一个内存位置(比如2000)。当您的代码使用my_var_a
时,解释器会查看位置2000,查看它是否指向1000,然后从1000中获取实际字符串值

当您调用
parse\u set(my\u var\u a)
时,Ruby实际上创建了一个名为
my\u var\u set
的新引用,并将其指向
my\u var\u a
指向的字符串(内存位置1000)。然而,
my_var_集
my_var_a
引用的副本——比如说
my_var_集
是在内存位置3000处创建的
my_var_a
my_var_set
是内存中两个完全不同的引用,它们恰好指向保存字符串值的相同内存位置

parse\u set
中的语句
my\u var\u set=“my value changed”
在内存中创建一个新字符串,并将
my\u var\u set
指向该新内存位置。但是,这不会改变原始的
my\u var\u a
参考点所在的位置!既然
my\u var\u set
指向不同的内存位置,您对该变量所做的任何操作都不会影响
my\u var\u a

同样的引用副本也适用于
parse_sub
。但是
parse\u sub
更改字符串的原因是,您直接在
my\u var\u sub
引用上调用一个方法。执行此操作时,解释器将获取
my\u var\u sub
指向的对象,然后对其进行修改。因此,该更改将显示在
my_var\u 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!、capitalize!、chomp!、等)某些更改接收器的后缀不是!(替换为一个)。如果调用更改接收器的方法,则对该对象的任何和所有引用都将看到更改。如果调用一个不改变接收方的方法,该方法将返回一个新字符串

gsub不修改接收器,而是返回字符串的新实例:

a = "foo"
b = a
p a.sub(/o/, '#')     # "f##"
p a                   # => "foo"
p b                   # => "foo"
gsub!是否修改接收器:

a = "foo"
b = a
p a.sub!(/o/, '#')    # => "f#o"
p a                   # => "f#o"
p b                   # => "f#o"
“如何避免使用sub!但却产生相同的结果?”

将其设置为对象的实例变量(尽管这仅适用于主脚本,但如果您希望使用实例变量方法,我建议您创建自己的类)


你能换个说法吗?我真的不明白关于重新打印的部分:)(我还更改了变量名以减少歧义),我如何在不使用可笑的sub的情况下更改值!还有regex?我补充了一些信息,希望能让事情变得更清楚。按值传递引用是复杂的,需要一段时间才能了解发生了什么。另外,要在不使用sub的情况下更改值,只需让
parse
方法返回一个值,并将其分配给原始变量:
my\u var\u a=some\u parse\u method(my\u var\u a)
。哇,这是一个非常好且简单的解释。非常感谢。“按值传递引用”是描述Ruby工作原理最准确的方法。感谢您指出替换方法。但是卡莱布的回答向我解释了内部情况,这样我才能理解发生了什么,否则我会接受你的回答:D
@my_var_a = "nothing happend to me"

def parse_set()
  @my_var_a = "my value changed"
end