从外部方法跳过Ruby迭代器



假设您有一个Ruby迭代器,它在其块中使用了一个外部方法:

def external_method(n)
n.valid? ? n : next  #this "next" expression will result in an error 
end
(1..9).map { |i| external_method(i) } 

真正的问题是如何从迭代器内部使用的外部方法中breaknext

是否可以将next移动到map块中?类似这样的东西:

def external_method(n)
n.valid? && n
end
(1..9).map { |i| external_method(i) || next }

顺便说一句,我不确定你问题中的代码只是一个例子还是真实的代码。但在我看来,next没有任何意义,因为它在块中被调用为最后一个,无论如何,移动到下一个元素都是map的下一步。

真正的问题是如何从迭代器内部使用的外部方法中breaknext

def external_method(n)
n.valid? ? n : next
end

即使有可能,我也很难理解这种方法的作用。您不应该试图从迭代之外显式地控制迭代。

从外部方法向循环返回有效值怎么样?(不一定是n,你也可以得到一个修改后的值(

def external_method(n)
yield n if n.valid?
end
(1..9).map do |i|
external_method(i) do |n|
# do something with n
end
end

这样,该块将仅在n.valid?的情况下执行,否则跳过。您可能需要调整external_method的返回值才能很好地使用map。它当前只返回块的结果或nil

Ruby 2.7具有可枚举的#filter_map
(1..10).filter_map { |i| i * 2 if i.even? } #=> [4, 8, 12, 16, 20]

(链接文档中的示例(

如果external_method需要做很多事情,但只有当n上的一个条件得到满足时,你才能始终返回,除非该条件得到满足,这会产生中断或跳到下一次迭代的效果,因为方法调用是块中唯一的操作:

def external_method(n)
return unless n.even?
puts "running block on #{n}"
end
(1..9).map { |i| external_method(i) }

如果块不仅仅有方法调用,并且根据方法调用中的条件,您希望跳过块的所有其余部分,可以尝试ruby的throw/catch:

def external_method(n)
throw :next unless n.even?
end
(1..9).map do |i|
catch(:next) do
external_method(i)
puts "running block on #{i}"
end
end

这两个代码段输出:

running block on 2
running block on 4
running block on 6
running block on 8

最新更新