为什么 str.next!在 Enumerable#map 中用相同的元素填充数组?
Why does the str.next! in an Enumerable#map fill the array with same elements?
Enumerable#map
在生成后在块中创建一个包含 return 值的数组。
在这种情况下,说:
v = 'a'
26.times.map { |i| v.ord.+(i).chr }
# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
但为什么下面的代码会用相同的元素填充数组?
v = '`'
26.times.map { v.next! }
# => ["z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z"]
v = '`'
Array.new(26) { v.next! }
# => ["z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z"]
他们不应该都有元素 a 到 z 吗?
同样有效:
v = '`'
Array.new(26) { v = v.succ }
# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
实际上我正在尝试做:
v = "\xf0\x9d\x93\xa9"
('a'..'z').reduce({}) { |h, i| h.merge(i.intern => v = v.succ) }
# => {:a=>"", :b=>"", :c=>"", :d=>"", :e=>"", :f=>"", :g=>"", :h=>"", :i=>"", :j=>"", :k=>"", :l=>"", :m=>"", :n=>"", :o=>"", :p=>"", :q=>"", :r=>"", :s=>"", :t=>"", :u=>"", :v=>"", :w=>"", :x=>"", :y=>"", :z=>""}
但是我在使用 succ!
/ next!
时得到了所有的 z
v = "\xf0\x9d\x93\xa9"
('a'..'z').reduce({}) { |h, i| h.merge(i.intern => v.succ!) }
# => {:a=>"", :b=>"", :c=>"", :d=>"", :e=>"", :f=>"", :g=>"", :h=>"", :i=>"", :j=>"", :k=>"", :l=>"", :m=>"", :n=>"", :o=>"", :p=>"", :q=>"", :r=>"", :s=>"", :t=>"", :u=>"", :v=>"", :w=>"", :x=>"", :y=>"", :z=>""}
除了succ!
/ next!
不改变内存位置和object_id,v.succ!
和v = v.succ
不一样吗?
当您对变量 str
调用 next!
或 succ!
时,分配给该变量的对象会发生变化,并返回对该对象的引用。如果 str = 'a'
并且您调用 str.next!
26 次,则 str 变为 z
。每次调用 next!
时,都会返回对同一对象的引用。结果,您得到一个包含 26 个对同一对象的引用的数组。这就是数组中所有元素都相同的原因。
您可以通过检查数组元素的 object_id
来测试它:
pry(main)> str = 'a'
'a'
pry(main)> array = 3.times.map{ str.next!}
=> ["d", "d", "d"]
pry(main)> array.map(&:object_id)
=> [47056742362940, 47056742362940, 47056742362940]
pry(main)> array.map(&:object_id).uniq
=> [47056742362940]
当您编辑 str
时,所有数组元素都会更新:
[39] pry(main)> str << "b"
=> "db"
[40] pry(main)> array
=> ["db", "db", "db"]
[41] pry(main)> str.replace
str.replace
[41] pry(main)> str.replace('a')
=> "a"
[42] pry(main)> array
=> ["a", "a", "a"]
如果你想要一个包含整个字母表的数组,你需要在更改当前字母后复制字符串,如下所示:
[25] pry(main)> str = 'a'
=> "a"
[26] pry(main)> 25.times.map{ str.next!.dup}
=> ["b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"w",
"x",
"y",
"z"]
您还可以使用范围:
[32] pry(main)> ('a'..'z').to_a
=> ["a",
"b",
"c",
"d",
"e",
"f",
...
Enumerable#map
在生成后在块中创建一个包含 return 值的数组。
在这种情况下,说:
v = 'a'
26.times.map { |i| v.ord.+(i).chr }
# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
但为什么下面的代码会用相同的元素填充数组?
v = '`'
26.times.map { v.next! }
# => ["z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z"]
v = '`'
Array.new(26) { v.next! }
# => ["z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z"]
他们不应该都有元素 a 到 z 吗?
同样有效:
v = '`'
Array.new(26) { v = v.succ }
# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
实际上我正在尝试做:
v = "\xf0\x9d\x93\xa9"
('a'..'z').reduce({}) { |h, i| h.merge(i.intern => v = v.succ) }
# => {:a=>"", :b=>"", :c=>"", :d=>"", :e=>"", :f=>"", :g=>"", :h=>"", :i=>"", :j=>"", :k=>"", :l=>"", :m=>"", :n=>"", :o=>"", :p=>"", :q=>"", :r=>"", :s=>"", :t=>"", :u=>"", :v=>"", :w=>"", :x=>"", :y=>"", :z=>""}
但是我在使用 succ!
/ next!
v = "\xf0\x9d\x93\xa9"
('a'..'z').reduce({}) { |h, i| h.merge(i.intern => v.succ!) }
# => {:a=>"", :b=>"", :c=>"", :d=>"", :e=>"", :f=>"", :g=>"", :h=>"", :i=>"", :j=>"", :k=>"", :l=>"", :m=>"", :n=>"", :o=>"", :p=>"", :q=>"", :r=>"", :s=>"", :t=>"", :u=>"", :v=>"", :w=>"", :x=>"", :y=>"", :z=>""}
除了succ!
/ next!
不改变内存位置和object_id,v.succ!
和v = v.succ
不一样吗?
当您对变量 str
调用 next!
或 succ!
时,分配给该变量的对象会发生变化,并返回对该对象的引用。如果 str = 'a'
并且您调用 str.next!
26 次,则 str 变为 z
。每次调用 next!
时,都会返回对同一对象的引用。结果,您得到一个包含 26 个对同一对象的引用的数组。这就是数组中所有元素都相同的原因。
您可以通过检查数组元素的 object_id
来测试它:
pry(main)> str = 'a'
'a'
pry(main)> array = 3.times.map{ str.next!}
=> ["d", "d", "d"]
pry(main)> array.map(&:object_id)
=> [47056742362940, 47056742362940, 47056742362940]
pry(main)> array.map(&:object_id).uniq
=> [47056742362940]
当您编辑 str
时,所有数组元素都会更新:
[39] pry(main)> str << "b"
=> "db"
[40] pry(main)> array
=> ["db", "db", "db"]
[41] pry(main)> str.replace
str.replace
[41] pry(main)> str.replace('a')
=> "a"
[42] pry(main)> array
=> ["a", "a", "a"]
如果你想要一个包含整个字母表的数组,你需要在更改当前字母后复制字符串,如下所示:
[25] pry(main)> str = 'a'
=> "a"
[26] pry(main)> 25.times.map{ str.next!.dup}
=> ["b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"w",
"x",
"y",
"z"]
您还可以使用范围:
[32] pry(main)> ('a'..'z').to_a
=> ["a",
"b",
"c",
"d",
"e",
"f",
...