将数组传递给 Array#each,内部使用引用或值

发布于 2024-10-21 00:48:00 字数 272 浏览 2 评论 0原文

array1 = [0, 1]

# CASE 1:  
[array1].each do |arr| 
  arr = [3, 4] 
end

=> [0, 1]

# CASE 2:
[array1].each do |arr| 
  arr.delete_if { |ele| ele == 0 }
end

=> [[1]]

我认为 ruby​​ 总是通过引用传递数组。为什么在 CASE 1 中它没有改变数组的值,但在 CASE 2 中却改变了它?谢谢。

array1 = [0, 1]

# CASE 1:  
[array1].each do |arr| 
  arr = [3, 4] 
end

=> [0, 1]

# CASE 2:
[array1].each do |arr| 
  arr.delete_if { |ele| ele == 0 }
end

=> [[1]]

I thought ruby always passes array by reference. Why didn't it change the value of array in CASE 1 but did change it in CASE 2? thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

哎呦我呸! 2024-10-28 00:48:00

在第一种情况下,您所做的只是更改 arr 指向的对象 - 您实际上并未修改原始对象。这可以通过以下脚本来证明:

# Given our test value...
test_array = [1, 2]

# we can verify the values and the object_ids
puts "Value of `test_array`: #{test_array.inspect}"
puts "Object_id of `test_array`: #{test_array.object_id}"

# now, let's put it in a container and run it through a block
@array_container = [test_array]

@array_container.each do |arr|

  # Just to prove that `arr` points at test_array
  puts "Object_id of `arr`: #{arr.object_id}"

  # and that it's the same as the first element in our container
  puts "@container.first.object_id: #{@array_container.first.object_id}"

  # but, when we re-assign our block variable
  arr = [3, 4]

  # we get different values
  puts "Object_id of `arr`: #{arr.object_id}"
  puts "@container.first.object_id: #{@array_container.first.object_id}"
end

哪些输出...

Value of `test_array`: [1, 2]
Object_id of `test_array` : 2150710260

Object_id of `arr`        : 2150710260
@container.first.object_id: 2150710260

Object_id of `arr`        : 2150708040
@container.first.object_id: 2150710260

那么案例 2 有何不同?在情况 2 中,您实际上调用了一个自毁性方法,该方法将对 arr 引用的原始对象进行更改

In your first situation, all you've done is change which object arr points at - you haven't actually modified the original. This can be proven with the following script:

# Given our test value...
test_array = [1, 2]

# we can verify the values and the object_ids
puts "Value of `test_array`: #{test_array.inspect}"
puts "Object_id of `test_array`: #{test_array.object_id}"

# now, let's put it in a container and run it through a block
@array_container = [test_array]

@array_container.each do |arr|

  # Just to prove that `arr` points at test_array
  puts "Object_id of `arr`: #{arr.object_id}"

  # and that it's the same as the first element in our container
  puts "@container.first.object_id: #{@array_container.first.object_id}"

  # but, when we re-assign our block variable
  arr = [3, 4]

  # we get different values
  puts "Object_id of `arr`: #{arr.object_id}"
  puts "@container.first.object_id: #{@array_container.first.object_id}"
end

Which outputs...

Value of `test_array`: [1, 2]
Object_id of `test_array` : 2150710260

Object_id of `arr`        : 2150710260
@container.first.object_id: 2150710260

Object_id of `arr`        : 2150708040
@container.first.object_id: 2150710260

So how is that different in Case 2? In case 2, you're actually calling a self-destructive method, which will make changes to the original object that is being referenced by arr

云之铃。 2024-10-28 00:48:00

我认为你的问题与范围有关。 do-end 构造实际上是一个新块,因此当您声明 arr = [3, 4] 时,您正在实例化一个新的 arr = [3, 4 ] 在该块内。而在情况 2 中,您直接修改引用。在案例 1 中做同样的事情会是这样的:

[array1].each do |arr| 
  arr.each_index do |i|
    arr[i]+=3
  end 
end

=> [[3,4]]

I think your issue has to do with scope. The do-end construct is really a new block, so when you declare arr = [3, 4] you are instantiating a new arr = [3, 4] within that block. Whereas in Case 2 you are modifying the reference directly. To do the same thing in Case 1 would be something like:

[array1].each do |arr| 
  arr.each_index do |i|
    arr[i]+=3
  end 
end

=> [[3,4]]

.each 只是依次调用该块及其所调用的集合的每个元素(在本例中为 [array1])。传递参数只是将其分配给参数。您的示例可以简化为以下内容:

# CASE 1:  
array1 = [0, 1]
arr = array1
arr = [3, 4]
array1

=> [0, 1]

# CASE 2:
array1 = [0, 1]
arr = array1
arr.delete_if { |ele| ele == 0 }
array1

=> [1]

.each simply calls the block with each element of the collection it's called on (in this case [array1]) in turn. Passing an argument just assigns it to a parameter. Your example can be simplified to the following:

# CASE 1:  
array1 = [0, 1]
arr = array1
arr = [3, 4]
array1

=> [0, 1]

# CASE 2:
array1 = [0, 1]
arr = array1
arr.delete_if { |ele| ele == 0 }
array1

=> [1]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文