jj_*_*jj_ 6 ruby arrays each block enumerator
好吧也许这很简单,但是......鉴于此:
arr = ("a".."z").to_a
arr
=> ["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"]
Run Code Online (Sandbox Code Playgroud)
..而且我正在尝试将所有"arr"值更改为"bad"
为什么没有这方面的工作?
arr.each { |v| v = "bad" }
arr
=> ["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"]
Run Code Online (Sandbox Code Playgroud)
答案表明"v"是块的局部变量(数组值的"副本"),我完全明白(以前从未困惑过我)但是
..如果数组元素是对象,它为什么工作?
class Person
def initialize
@age = 0
end
attr_accessor :age
end
kid = Person.new
man = Person.new
arr = [kid, man]
arr.each { |p| p.age = 50 }
arr[0]
=> #<Person:0xf98298 @age=50>
Run Code Online (Sandbox Code Playgroud)
这里的"p"还不在这里吗?但那真的影响了对象,怎么样?
iai*_*ain 11
我将扩展@pst的评论:
为什么这不起作用?
arr.each { |v| v = "bad" }
Run Code Online (Sandbox Code Playgroud)
因为each
遍历数组并将每个项放入您作为局部变量给出的块中v
,因为v
它不是对数组的引用arr
.
new_arr = arr.each { |v| v = "bad" }
Run Code Online (Sandbox Code Playgroud)
each
因为你会使用map
(不参考@ benjaminbenben的答案).因此,分配它不"有效".
arr.each { |v| arr[arr.index v] = "bad" }
Run Code Online (Sandbox Code Playgroud)
在这里,你把每个项目arr
到局部变量v
,但你也提到了阵列本身的块,因此你能够分配给数组,并使用局部变量v
找到对应的内容的索引v
(但是你可能会发现当项目并非都是唯一的时候,这将无法正常工作.
arr.each { |p| p.age = 50 }
kid.age #-> 50
Run Code Online (Sandbox Code Playgroud)
在这里,您再次填充了p
每个项目/对象的局部变量arr
,但之后您通过方法访问了每个项目,因此您可以更改该项目 - 您不会更改数组.它是不同的,因为引用是局部变量的内容,你混淆了它是对数组的引用.它们是分开的东西.
回应以下评论:
arr[0]
# => #<Person:0xf98298 @age=50>
Run Code Online (Sandbox Code Playgroud)
这完全取决于谁在何时提到谁.
试试这个:
v = Person.new
# => #<Person:0x000001008de248 @age=0>
w = Person.new
# => #<Person:0x000001008d8050 @age=0>
x = v
# => #<Person:0x000001008de248 @age=0>
v = Person.new
# => #<Person:0x00000100877e80 @age=0>
arr = [v,w,x]
# => [#<Person:0x00000100877e80 @age=0>, #<Person:0x000001008d8050 @age=0>, #<Person:0x000001008de248 @age=0>]
Run Code Online (Sandbox Code Playgroud)
v
在那里提到了2个不同的对象.v
这不是一个固定的东西,它是一个名字.首先它指的是#<Person:0x000001008de248 @age=0>
,然后它指的是#<Person:0x00000100877e80 @age=0>
.
现在试试这个:
arr.each { |v| v = "bad" }
# => [#<Person:0x00000100877e80 @age=0>, #<Person:0x000001008d8050 @age=0>, #<Person:0x000001008de248 @age=0>]
Run Code Online (Sandbox Code Playgroud)
它们都是对象,但没有更新或"工作".为什么?因为首次输入块时,v
引用数组中已生成(给定)的项.所以在第一次迭代v
是#<Person:0x00000100877e80 @age=0>
.
但是,我们然后分配"bad"
给v
.我们没有分配"bad"
给数组的第一个索引,因为我们根本没有引用数组.arr
是对数组的引用.放在arr
块内,你可以改变它:
arr.each { |v|
arr[0] = "bad" # yes, a bad idea!
}
Run Code Online (Sandbox Code Playgroud)
为什么然后arr.each { |p| p.age = 50 }
更新数组中的项目?因为p
指的是也恰好在数组中的对象.在第一次迭代时p
引用的对象也称为kid
,并且kid
有一个age=
方法并且你会坚持50
下去.kid
也是数组中的第一个项目,但你所说的kid
不是数组.你可以这样做:
arr.each { |p| p = "bad"; p.age }
NoMethodError: undefined method `age' for "bad":String
Run Code Online (Sandbox Code Playgroud)
首先,p
提到也恰好在数组中的对象(就是它产生的地方),但后来p
被引用"bad"
.
each
迭代数组并在每次迭代时产生一个值.您只获得值而不是数组.如果要更新阵列,请执行以下操作:
new_arr = arr.map{|v| v = "bad" }
new_arr = arr.map{|v| "bad" } # same thing
Run Code Online (Sandbox Code Playgroud)
要么
arr.map!{|v| v = "bad"}
arr.map!{|v| "bad"} # same thing
Run Code Online (Sandbox Code Playgroud)
as map
返回一个填充了块的返回值的数组.map!
将使用填充了块的返回值的数组更新您调用它的引用.一般来说,无论如何迭代它时更新对象是个坏主意.我发现将它想象为创建一个新数组总是更好,然后你可以使用这些!
方法作为捷径.