假设我有一个对象x
和一个包含y=[x]
的数组x
。如果我操纵x
,则y
不会改变:
x = 1 # => 1
y = [x] # => [1]
x = x+1 # => 2
x # => 2
y # => [1]
如果我更改y
,则x
不会更改。
x = 1 # => 1
y = [x] # => [1]
y.map!{|a| a+1} # => [2]
y # => [2]
x # => 1
有没有办法让它们并行改变?感觉就像我在数组上map!
时,底层值应该改变。
答案 0 :(得分:3)
首先
x = x + 1
将使用旧名称x
x = 1
y = [x]
x.object_id
# 3
y[0].object_id
# 3
x = x + 1
x.object_id
# 5
y[0].object_id
# 3
其次,数字是Ruby中的不可变对象(例如,字符串是可变的)。所以你不能使用Ruby中的数字对象做你想做的事。你能做的就是更加模糊。您可以创建自己的可变对象(数字的容器)并在数组中使用对该对象的引用。
class MutableNumber
attr_accessor :n
def initialize(n)
@n = n
end
end
x = MutableNumber.new(1)
y = [x]
y[0].n
#=> 1
x.n += 1
y[0].n
#=> 2
你可以更进一步,在这里添加更多魔法来模仿数字
class MutableNumber
attr_accessor :n
def initialize(n)
@n = n
end
def method_missing(m, *args, &blk)
@n = @n.send(m, *args, &blk)
self
end
end
x = MutableNumber.new(1)
y = [x]
y[0].n
#=> 1
x += 1
y[0].n
#=> 2
但我不鼓励你这样做。
坚持认为数字是不可变的。总的来说,你应该小心可变性。
答案 1 :(得分:0)
map!
对于数组是可变的,而不是对于它的元素。这意味着数组在适当的位置获得新值(即它被分配给原始数组)。数组中的元素不会发生变异,而是被新元素替换。
如果要更改旧值,可以使用each
进行迭代,并在每个元素上调用mutating方法。您可以通过字符串数组看到这一点:
a = "a"; b = "b"; aa = [a, b]
#=> ["a", "b"]
aa.map!{|e| e.capitalize }
#=> ["A", "B"]
[a, b]
#=> ["a", "b"]
a = "a"; b = "b"; aa = [a, b]
#=> ["a", "b"]
aa.each{|e| e.capitalize! }
#=> ["A", "B"]
[a, b]
#=> ["A", "B"]
请注意,它不适用于不可变对象,数字是不可变的,正如@ fl00r在他的回答中所解释的那样。