问题 从外部方法调用ruby循环上的next


在Ruby中,很容易告诉循环转到下一个项目

(1..10).each do |a|
  next if a.even?
  puts a
end

result =>

1
3   
5
7
9

但是如果我需要从循环外部调用next(例如:方法)怎么办?

def my_complex_method(item)
  next if item.even?  # this will obviously fail 
end

(1..10).each do |a|
  my_complex_method(a)
  puts a
end

我发现的唯一解决方案就是使用 throw & catch 喜欢在SO问题中 如何在Ruby中打破外循环?

def my_complex_method(item)
  throw(:skip) if item.even? 
end

(1..10).each do |a|
  catch(:skip) do   
    my_complex_method(a)
    puts a
  end
end

我的问题是:任何人都有更多的琐事解决方案吗?或是 throw/catch 只有这样做?

如果我想打电话也是如此 my_complex_method 不仅作为该循环的一部分(=>不抛出:跳过),我能以某种方式告诉我的方法它是从循环中调用的吗?


10687
2017-07-09 10:59


起源

你真的, 真 过去想这个。返回一个值并调用 next 有条件地基于返回值。这是一 令人难以置信 软件中的常见模式,几乎我用过的每种语言。 throw/catch 在这里没有地方。 - meagar♦
我同意这个例子很荒谬,但我有一个案例需要分离循环和方法 - equivalent8


答案:


你复杂的方法可以返回一个布尔值,然后你在你的循环上进行比较,如下所示:

def my_complex_method(item)
  true if item.even? 
end

(1..10).each do |a|
  next if my_complex_method(a)
  puts a
end

一个简单的方法,但不同于尝试捕获一个。

UPDATE

item.even? 已经返回一个布尔值,你不需要 true if item.even? 部分,你可以这样做:

def my_complex_method(item)
  item.even? 
end

13
2017-07-09 11:13



我会回答这个问题,因为它让我意识到了这一点 my_complex_method 在我的真实代码中可以用不同的方式编写,这样就可以实现(以及Meagar对我的问题的评论)......但是如果有人需要使用我在我的问题中描述的功能,我会去 Pritis回答 而不是我的 throw/catch 解 - equivalent8


Enumerator#next 和 Enumerator#peek 将是goo的好选择:

def my_complex_method(e)
  return if e.peek.even? 
  p e.peek
end
enum = (1..5).each
enum.size.times do |a|
  my_complex_method(enum)
  enum.next
end

产量

1
3
5

1
2017-07-09 11:17





如果您只需要根据返回的值对某些值执行操作 my_complex_method 你可以明智地使用枚举器:

(1..10).map { |a| [a, my_complex_method(a)] }.each do |a, success|
  puts a if success
end
您可以定义方法接受块,并根据成功或失败在此块中执行一些操作:     (1..10)。每个人做| a |       my_complex_method {|成功|接下来如果成功}     结束 由于范围界定,您无法使用`catch` /`throw`,并根据处理状态调用`next`。

0
2017-07-09 11:20



据我所知,第一种方法不起作用 - next 没有通过 each - Frederick Cheung
啊,你是对的 - next 这里指的是定义的产量 my_complex_method... - samuil