我偶然发现了一些我不太了解的事情。我知道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!
但结果相同?
答案 0 :(得分:12)
my_var_a
和my_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
指向的字符串(内存位置1000)。但是,my_var_set
是my_var_a
引用的副本 - 假设my_var_set
是在内存位置3000创建的。my_var_a
和my_var_set
是2个完全不同的引用在内存中,它们恰好指向保存字符串值的同一个精确内存位置。
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
引用中,因为它仍指向相同的字符串。
答案 1 :(得分:5)
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##"
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"
答案 2 :(得分:0)
“我怎样才能避免使用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