为什么对带有感叹号的方法的新调用会影响该方法的所有先前调用?

Why a new call of a method with exclamation mark affects all previous calls of that method?

如果这是重复的,我很抱歉 - 我在现有帖子中找不到任何类似的内容。

我了解 shuffleshuffle! 等方法之间的区别。但是,我很困惑为什么多次调用该方法会导致更改以前引用它的所有对象的变量?我希望一旦我们应用了一个方法,变量就会得到一个值,我们就完成了它。并不是说它继续引用方法调用和传递的参数,而是稍后会重新评估它。

我认为最好用一个例子来演示:

irb(main):001:1* def shuffle(arr)
irb(main):002:1*   arr.shuffle!
irb(main):003:0> end
=> :shuffle
irb(main):004:0> arr = [1,2,3,4]
=> [1, 2, 3, 4]
irb(main):005:0> one = shuffle(arr)
=> [4, 2, 3, 1]
irb(main):006:0> two = shuffle(arr)
=> [1, 2, 4, 3]
irb(main):007:0> one
=> [1, 2, 4, 3]

所以,我希望 one 保持 [4, 2, 3, 1]。但是,对于每个新调用,所有先前的调用都将等同于方法调用的最新结果。我意识到它应该与使用相同的参数 arr 调用它有关,但仍然不太有意义。

Array#shuffle! 就地打乱数组,returns 它的接收者:

ary = [1, 2, 3, 4]
ary.equal?(ary.shuffle!) #=> true

shuffle! 的结果分配给另一个变量不会改变这一点。它只会导致两个变量引用同一个数组:

a = [1, 2, 3, 4]
b = a.shuffle!

a #=> [2, 4, 1, 3]
b #=> [2, 4, 1, 3]

a.equal?(b) #=> true

您可能需要一个 数组。这就是 Array#shuffle(没有 !)的用途:

a = [1, 2, 3, 4]
b = a.shuffle

a #=> [1, 2, 3, 4]
b #=> [2, 4, 1, 3]

即使shufflereturns原顺序的元素,你也会得到另一个数组实例:

a = [1, 2, 3, 4]
b = a.shuffle until b == a

a #=> [1, 2, 3, 4]
b #=> [1, 2, 3, 4]

a.equal?(b) #=> false