数组元素修改行为错误
Array element modification behaves wrong
我有一个填充有默认字符串的数组,我试图在随机位置替换默认字符串中的部分字符。
如果我这样做,我将更改数组中的所有元素:
arr = ["*"] * 10
arr[0][0..2] = "aaa"
arr
# => ["aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa"]
但是如果我以不同的方式初始化数组,它会起作用:
(0..10).each.map {|i| arr[i] = "*"}
arr[0][0..2] = "aaa"
arr
# => ["aaa", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*"]
更多,初始化和所有元素相同:
str = "*"
(0..10).each.map {|i| arr[i] = str}
arr[0][0..2] = "aaa"
arr
# => ["aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa"]
相反,我这样做是为了用独特的元素初始化它:
str = "*"
(0..10).each.map {|i| arr[i] = "#{str}" }
arr[0][0..2] = "aaa"
arr
# => ["aaa", "*", "*", "*", "*", "*", "*", "*", "*", "*"]
这种行为的背景是什么?
当您执行 arr=["*"]*10
时,您将完全相同的 String
对象放入所有数组槽中。然而,(0..10).each.map { |i| arr[i] = "*" }
正在为数组中的每个元素创建一个新的 String
对象。
用以下代码说明:
(0..10).each.map { |i| arr[i] = "*" }
arr[0].equal? arr[1] # Check if first and second elements point to same Object
# => false
arr = ["*"] * 10
arr[0].equal? arr[1]
# => true
数组存储对对象的引用。当你以这种方式初始化一个数组时,你会得到一个包含十个对同一个字符串的引用的数组。然后你修改字符串。
arr = ['*']*3
# => ["*", "*", "*"]
arr.map &:object_id
# => [70305424624600, 70305424624600, 70305424624600]
相比之下,这种方式 ruby 为每个元素分配一个新字符串:
Array.new(3){ '*' }.map &:object_id
# => [70184497001120, 70184497001060, 70184497001000]
arr = ["*"]*10
此语句创建一个包含 10 个元素的数组,但所有这些元素都不是唯一的,并且引用您在填充数组之前创建的字符串 "*"" 的同一个实例。我的意思是你的代码是一样的:
a = "*"
arr = [a, a, a, a, a, a, a, a, a, a]
#=> ["*", "*", "*", "*", "*", "*", "*", "*", "*", "*"]
arr.map(&:object_id)
#=> [15424420, 15424420, 15424420, 15424420, 15424420, 15424420, 15424420, 15424420, 15424420, 15424420]
数组的所有元素都引用同一个字符串实例,因此当您更改数组中的任何元素值时,您实际上会更改 a 变量的值,因此作为结果你会得到相同的数组,其中填充了 a 变量,但是由于它的值被更改为 "aaa" 那么输出看起来像:
["aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa"]
在第二个示例中,您使用 "*" 字符串的新实例填充数组的每个元素,因此当您更改单个数组值时,它只会影响这个具体元素array 和所有其他的都是一样的,因为它们指的是内存中分配的不同对象。
arr = (0..10).each.map { |i| arr[i] = "*" }
#=> ["*", "*", "*", "*", "*", "*", "*", "*", "*", "*"]
arr.map(&:object_id)
#=> [14451520, 14451500, 14451480, 14451440, 14451420, 14451320, 14451300, 14451280, 14451260, 14451240, 14451160]
我有一个填充有默认字符串的数组,我试图在随机位置替换默认字符串中的部分字符。
如果我这样做,我将更改数组中的所有元素:
arr = ["*"] * 10
arr[0][0..2] = "aaa"
arr
# => ["aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa"]
但是如果我以不同的方式初始化数组,它会起作用:
(0..10).each.map {|i| arr[i] = "*"}
arr[0][0..2] = "aaa"
arr
# => ["aaa", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*"]
更多,初始化和所有元素相同:
str = "*"
(0..10).each.map {|i| arr[i] = str}
arr[0][0..2] = "aaa"
arr
# => ["aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa"]
相反,我这样做是为了用独特的元素初始化它:
str = "*"
(0..10).each.map {|i| arr[i] = "#{str}" }
arr[0][0..2] = "aaa"
arr
# => ["aaa", "*", "*", "*", "*", "*", "*", "*", "*", "*"]
这种行为的背景是什么?
当您执行 arr=["*"]*10
时,您将完全相同的 String
对象放入所有数组槽中。然而,(0..10).each.map { |i| arr[i] = "*" }
正在为数组中的每个元素创建一个新的 String
对象。
用以下代码说明:
(0..10).each.map { |i| arr[i] = "*" }
arr[0].equal? arr[1] # Check if first and second elements point to same Object
# => false
arr = ["*"] * 10
arr[0].equal? arr[1]
# => true
数组存储对对象的引用。当你以这种方式初始化一个数组时,你会得到一个包含十个对同一个字符串的引用的数组。然后你修改字符串。
arr = ['*']*3
# => ["*", "*", "*"]
arr.map &:object_id
# => [70305424624600, 70305424624600, 70305424624600]
相比之下,这种方式 ruby 为每个元素分配一个新字符串:
Array.new(3){ '*' }.map &:object_id
# => [70184497001120, 70184497001060, 70184497001000]
arr = ["*"]*10
此语句创建一个包含 10 个元素的数组,但所有这些元素都不是唯一的,并且引用您在填充数组之前创建的字符串 "*"" 的同一个实例。我的意思是你的代码是一样的:
a = "*"
arr = [a, a, a, a, a, a, a, a, a, a]
#=> ["*", "*", "*", "*", "*", "*", "*", "*", "*", "*"]
arr.map(&:object_id)
#=> [15424420, 15424420, 15424420, 15424420, 15424420, 15424420, 15424420, 15424420, 15424420, 15424420]
数组的所有元素都引用同一个字符串实例,因此当您更改数组中的任何元素值时,您实际上会更改 a 变量的值,因此作为结果你会得到相同的数组,其中填充了 a 变量,但是由于它的值被更改为 "aaa" 那么输出看起来像:
["aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa", "aaa"]
在第二个示例中,您使用 "*" 字符串的新实例填充数组的每个元素,因此当您更改单个数组值时,它只会影响这个具体元素array 和所有其他的都是一样的,因为它们指的是内存中分配的不同对象。
arr = (0..10).each.map { |i| arr[i] = "*" }
#=> ["*", "*", "*", "*", "*", "*", "*", "*", "*", "*"]
arr.map(&:object_id)
#=> [14451520, 14451500, 14451480, 14451440, 14451420, 14451320, 14451300, 14451280, 14451260, 14451240, 14451160]