为什么我的块只执行一次?

时间:2016-07-04 15:36:06

标签: ruby

为什么会这样:

array = (1..20).to_a
array.index.each_slice(5) do |slice|
  puts slice.inspect
end

返回:

[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
[11, 12, 13, 14, 15]
[16, 17, 18, 19, 20]

,同时:

other_array = []
array = (1..20).to_a
array.index.each_slice(5) do |slice|
  puts slice.inspect
  other_array.push(1)
end

仅返回:

[1, 2, 3, 4, 5]

other_array.push(1)如何打破块的执行?一个明显的结论是我无法访问不在块范围内的变量,但为什么会这样?

2 个答案:

答案 0 :(得分:6)

我在阵列文档中找到了解决方案。我想知道为什么你在数组中使用index函数时似乎只是想迭代数组。为此,您可以在不调用索引的情况下使用array.each_slice。 索引说:http://ruby-doc.org/core-2.2.0/Array.html#method-i-index

  

返回ary中第一个对象的索引,使对象为== to obj。

     

如果给出一个块而不是一个参数,则返回该块返回true的第一个对象的索引。如果未找到匹配则返回nil

因此,您的代码会对块进行评估,并检查结果是否为true。 在第一个示例中,您只执行返回puts的{​​{1}}。没错是假的 第二个示例返回包含单个1的数组的对象 在ruby中,如果不是niltrue,则每个条件都是false。 你可以在这里看到:

nil

因此,第二个示例中的块返回的内容不是-false,因此它不会再次运行,因为它找到了“有效”的结果。

对于返回,您可能应该知道ruby返回任何范围中的最后一个表达式,如果没有给出其他返回值。所以它返回if nil puts "foo" end => nil other_array = [1] if other_array puts "foo" end => "foo" 。 如果您不想重新格式化代码,可以执行以下操作:

other_array

这将强制该块返回other_array = [] array = (1..20).to_a array.index.each_slice(5) do |slice| puts slice.inspect other_array.push(1) nil end ,迭代将起作用。

答案 1 :(得分:2)

乍一看似乎很棘手,但是如果你查看文档的话 Array#index 如果没有给出阻止,您会看到此方法返回Enum

然后使用块调用#each_slice(n)对象上的Enum

在第一种情况下:

do |slice|
  puts slice.inspect
end

每次都会nil方法返回#index。如果您拨打array.index.each_slice(5) { nil }

,您将获得相同的结果

在第二个:

do |slice|
  puts slice.inspect
  other_array.push(1)
end

在块内部评估此块的值并将[1]返回到#index方法,因此它返回数组的第一个切片。如果您致电array.index.each_slice(5) { any_non_falsy_object }

,您将获得相同的结果