为什么我不能在一个方法中修改数组的值?

3
在下面的代码片段中,数组deck应该等于[6,9,5,6,5,1,2],因为Ruby通过引用传递数组。在方法调用后,deck的值没有改变。为什么会这样?
def count_cut!(deck)
  s1, s2 = deck[0, deck.last], deck[deck.last..-2]
  deck = s2 + s1 + [deck.last]
end

deck = [5, 1, 6, 9, 5, 6, 2]
count_cut!(deck)
p deck

我正在使用Ruby 1.9.2-p180版本。

4个回答

8

将值赋给deck并不会改变传入的数组。它在函数定义的作用域中被视为一个局部变量。如果你确实想要改变它,可以调用deck.replace


为什么 deck.replace 可以修改 deck 这个局部变量呢?这是赋值语句的一个特殊情况吗? - RaouL
2
当你调用 deck = s2 + s1 + [deck.last] 时,你创建了一个新的对象。如果你在方法分配后和 count_cut!(deck) 后使用 puts deck.object_id 进行测试,就可以验证它。 - Vasiliy Ermolovich
赋值是一个特殊情况,如果你想这样考虑的话。在 Ruby 中,所有的值都是按引用传递的,因此任何修改实例的方法都会对每个人都进行修改。但是赋值会将该变量更改为指向一个新实例。 - Austin Taylor
1
我相信 Ruby 按值传递引用 - Wayne Conrad

5
以 Ruby 的方式实现:不要修改原始数组,而是返回修改后的数组:
def count_cut(deck)
  s1, s2 = deck[0, deck.last], deck[deck.last..-2]
  s2 + s1 + [deck.last]
end

调用者随后将返回值分配给 deck
deck = [5, 1, 6, 9, 5, 6, 2]
deck = count_cut(deck)
p deck

但是考虑将所有内容封装在一个Deck类中,特别是如果一个牌组还有其他行为:
class Deck

  def initialize(cards)
    @cards = cards
  end

  def count_cut!
    s1, s2 = @cards[0, @cards.last], @cards[@cards.last..-2]
    @cards = s2 + s1 + [@cards.last]
  end

end

deck = Deck.new [5, 1, 6, 9, 5, 6, 2]
deck.count_cut!
p deck

2

Array的. +方法可以让你得到一个新的数组。使用.unshift来修改原始对象。

deck = [1,2,3,4,5]
p deck.object_id #some_number
deck = [6] + deck
p deck.object_id #another_number
deck.unshift([7])
p deck.object_id #unchanged 

1

你没有修改 deck 变量所引用的数组,而是只是将一个新的数组赋值给了局部变量 deck

deck = s2 + s1 + [deck.last]

上面的代码创建了一个新的数组,其内容为 s2 + s1 + [deck.last],然后将该新数组分配给本地变量 deck。原始的deck所引用的数组保持不变。如果你想改变这个数组,那么你需要像这样:

deck_last = deck.last
deck.clear
deck.push(*s2)
deck.push(*s1)
deck.push(deck_last)

否则,您将会丢失本地变量 deck 和其引用的非本地数组之间的连接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接