4

似乎在使用 splat 运算符通过引用将参数传递给块时,参数被复制了。

我有这个:

def method
  a = [1,2,3]
  yield(*a)
  p a
end

method {|x,y,z| z = 0}
#=> this puts and returns [1, 2, 3] (didn't modified the third argument)

如何通过引用传递这些参数?如果我直接传递数组似乎可以工作,但是 splat 运算符在这里会更加实用、直观和可维护。

4

4 回答 4

7
  1. 在 Ruby 中,当您编写时,x = value您正在创建一个新的局部变量x,无论它以前是否存在(如果它存在,则名称只是简单地重新绑定,原始值保持不变)。因此,您将无法以这种方式就地更改变量。

  2. 整数是不可变的。因此,如果您发送一个整数,则无法更改其值。请注意,您可以更改可变对象(字符串、哈希、数组...):

    def method
      a = [1, 2, "hello"]
      yield(*a)
      p a
    end
    
    method { |x,y,z| z[1] = 'u' }
    # [1, 2, "hullo"]
    

注意:我试图回答你的问题,现在我的观点是:更新方法或块中的参数会导致错误的代码(你不再有引用透明度)。如果愿意,返回新值并让调用者自己更新变量。

于 2012-07-31T18:00:49.707 回答
2

这里的问题是=标志。它使局部变量z分配给另一个对象。

以字符串为例:

def method
  a = ['a', 'b', 'c']
  yield(*a)
  p a
end

method { |x,y,z| z.upcase! }   # => ["a", "b", "C"]

这清楚地表明z与数组的第三个对象相同。

这里的另一点是你的例子是数字。Fixnums 有固定的 id;因此,您不能在保持相同对象 ID 的同时更改数字。要改变Fixnums,你必须使用=给变量分配一个新的数字,而不是像自改变的方法inc!(这样的方法不能存在于Fixnums上)。

于 2012-07-31T18:01:29.783 回答
0

是的...数组包含对象的链接。在您的代码中,当您使用yield(*a)then in 块时,您可以使用指向数组中对象的变量。现在寻找代码示例:

daz@daz-pc:~/projects/experiments$ irb
irb(main):001:0> a = 1
=> 1
irb(main):002:0> a.object_id
=> 3
irb(main):003:0> a = 2
=> 2
irb(main):004:0> a.object_id
=> 5

因此,在块中您不会更改旧对象,您只需创建另一个对象并将其设置为 variable。但是该数组包含指向旧对象的链接。

看看调试的东西:

def m
  a = [1, 2]
  p a[0].object_id
  yield(*a)
  p a[0].object_id
end

m { |a, b| p a.object_id; a = 0; p a.object_id }

输出:

3
3
1
3
于 2012-07-31T17:02:24.897 回答
0

如何通过引用传递这些参数?

您不能在 Ruby 中通过引用传递参数。Ruby 是按值传递的。总是。没有例外,没有如果,没有但是。

如果我直接传递数组似乎可以工作

我对此表示高度怀疑。您根本无法在 Ruby 中通过引用传递参数。时期。

于 2012-08-01T00:16:05.220 回答