Ruby是否为分配数组的变量处理与分配字符串的变量不同?

时间:2015-10-06 20:49:41

标签: arrays ruby string

我认为当你声明一个变量并为它赋一个字符串或数组时,你就是在创建一个字符串或数组的独立副本。此外,无论你对该变量做什么都不会影响原始变量。我的假设不适用于下面的第一组代码:

array = ["tubular", "bell", "single", "file"]
word = array[0]
word[0] = word[0].upcase 
array.join(" ") # => Tubular bell single file
word            # => Tubular
array[0]        # => Tubular

但它与第二个相关:

string = "ten aviators climbing isoceles"
word = string[0]
word = word.upcase 
string    # => ten aviators climbing isoceles
word      # => T
string[0] # => t

有人可以解释为什么在第一组代码中,将word[0]设置为word[0].upcase会导致我最初分配给变量bell_arr的数组word发生更改,但是在第二组代码中,如果变量分配了一个字符串,则不会发生类似的变化?

2 个答案:

答案 0 :(得分:2)

这必须处理我们在编程语言中称为可变性/不可变性和对象引用的问题。使用" Ruby"进行一些搜索和"不变性","参考"会带来一些好的结果,但基本上

array = ["tubular bell single", "bell", "single", "file"]

数组包含对某些Ruby对象的引用,这里是String个实例。 A" Ruby字符串"实际上是String类的一个实例。您的数组包含对String的某些实例的引用。

sentence = array[0] # Ruby terminal shows "tubular bell single"
# But actually, array[0] is a reference to a Ruby Object 

Array [0]是对字符串Object的引用,即。 array [0]就像一个指向字符串的指针。但是当你在Ruby终端中调用array[0]时,你实际上只对字符串表示感兴趣,而不是对象本身,所以在场景后面的Ruby调用了类似array [0] .to_string的东西,所以你可以看到字符串,而不仅仅是像#<Object:0x000000031082b0>这样的东西,这是Ruby在您的终端中写入对象的引用并按下回车时通常显示的内容。

现在不像其他编程语言(如C),下面没有&#34;&#34;一个String类,没有&#34;字符&#34;类。 String实例不是由对其他Ruby对象的引用组成的。

当您调用&#34;句子[0]&#34;时,这基本上意味着您希望将句子的第一个字母作为可以操作的Ruby对象。所以它确实在内存中创建了一个新的对象。

所以实际上first_letter = sentence[0]创建了一个字符串实例,它只是包含&#34; t&#34;

的字符串

但是,当你调用句子[0] =&#34; t&#34;时,你正在调用String实例上的一个特定方法,它基本上是这样的:用这个替换这个字母。执行此操作时,您正在修改实例本身!

编辑:也许以下内容会说清楚。 Ruby使用&#34;对象标识符&#34;识别每个对象的实例

a = "Hello World"
b = "Hello again"
c = "Hello World" # Same string representation as a

a.object_id # 26817860
b.object_id # 25401040
c.object_id # 25247200 # Note it's not the same number as a!

array = [a, b, c]

array[0].object_id # 26817860, so it's the instance of a !!

first_letter = a[0]  # Ruby shows "H"
first_letter.object_id # 23178100, a different object in memory

现在

a = "A new string"
a.object_id # 24367200, it's again new object in memory
array # ["Hello World", "Hello again", "Hello World"]
array[0].object_id # 26817860, our array[0] still points to the original object_id

但是

first_item = array[0] # "Hello World"
first_item.object_id # 26817860 alright, no magic trick, this is still the object_id of "a"
first_item[0] = "X"
first_item.object_id # 26817860 UNCHANGED ! We have really changed our instance and not created a new one !
array # ["Xello World", "Hello again", "Hello World"]

答案 1 :(得分:1)

这是因为word = string[0]创建了一个新的字符串实例。如果从字符串中取出的单个字符与原始字符串是相同的字符串实例,那么这意味着原始字符串的内容已被该单个字符替换。这太不方便了。 Ruby的String#[]不会这样做。它创建一个新的字符串实例。此外,word = word.upcase只是一个变量赋值。它使用旧的word并创建一个新变量word。它对旧的word没有任何作用(首先与string不同)。