为什么字符串替换会修改原变量的值?

5

我遇到了奇怪的问题,但不知道原因:

s = self.shopify_p
s.title
=> "Disco (Wholesale)"

现在我想要一个新的变量,其中包含s.title的内容,但不包括“(批发)”部分。 因此,我执行以下操作:

original_title = s.title
=> "Disco (Wholesale)" 
original_title[" (Wholesale)"] = ""
=> ""

现在如果我执行以下操作:
original_title
=> "Disco"

这没问题,但奇怪的是,最后的字符串替换似乎甚至影响了原始的s变量:

s.title
=> "Disco"

我真的不理解这个……你能告诉我这里发生了什么吗?

s.title 应该还是“Disco (Wholesale)”吗?或者不是了?

3个回答

10

因为你正在访问同一个对象,所以它是相同的。

irb(main):006:0> x = "aaaa"
=> "aaaa"
irb(main):007:0> y = x 
=> "aaaa"
irb(main):008:0> x.object_id 
=> 70358166435920
irb(main):009:0> y.object_id
=> 70358166435920
irb(main):010:0> 

你可以尝试的另一种方法是

original_title = s.title.gsub(" (Wholesale)","")

非常感谢,我已经使用 Ruby 一年多了,但我仍然不知道这个! - Augusto
如果你问我,这是相当奇怪的行为。 - Eduardo López

7

在执行original_title = s.title之后,original_titles.title引用了同一个对象。

如果要实际上将字符串复制一份,请使用Object#dup

original_title = s.title.dup

dup → an_object

生成一个obj的浅层副本...

或者使用String.new

original_title = String.new(s.title)

new(str="") → new_str

返回一个新的字符串对象,其中包含 str 的副本。


哇,谢谢!我真的不知道这个!现在它可以工作了!你知道有没有更深入解释这个的文章吗? - Augusto
这在《Ruby编程》-类、对象和变量中有详细介绍。 - Stefan

3

Ruby中的变量默认情况下引用它们所指向的对象,而不是复制它们。因此,如果您更改底层对象,任何包含对该对象引用的变量中的更改都将显示出来。

如果a、b、c和d都指向同一个对象,则任何一个变量的更改都会在所有变量中“改变”(通过)。

  a  b  c
   \ | /
   Object
     |
     d

如果您想保留原始值,您需要创建一个新变量。
irb(main):001:0> a = "Foo"
=> "Foo"
irb(main):002:0> b = a
=> "Foo"
irb(main):003:0> a << " Bar"
=> "Foo Bar"
irb(main):004:0> b
=> "Foo Bar"
irb(main):005:0> a
=> "Foo Bar"
irb(main):006:0> a += " Baz"
=> "Foo Bar Baz"
irb(main):007:0> a
=> "Foo Bar Baz"
irb(main):008:0> b
=> "Foo Bar"

对于你的情况,@wlad的gsub建议(请注意他没有使用gsub!)似乎是一个不错的选择。

original_title = s.title.gsub(" (Wholesale)","")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接