如何从红宝石块中突围?

你离开我真会死。 提交于 2020-02-27 12:50:26

这是Bar#do_things

class Bar   
  def do_things
    Foo.some_method(x) do |x|
      y = x.do_something
      return y_is_bad if y.bad? # how do i tell it to stop and return do_things? 
      y.do_something_else
    end
    keep_doing_more_things
  end
end

这是Foo#some_method

class Foo
  def self.some_method(targets, &block)
    targets.each do |target|
      begin
        r = yield(target)
      rescue 
        failed << target
      end
    end
  end
end

我曾考虑过使用加薪,但是我试图使其变得通用,所以我不想在Foo放任何具体内容。


#1楼

我希望能够突破一个障碍-有点像前进的goto,与循环实际上没有关系。 实际上,我想中断一个循环中的块而不终止循环。 为此,我使该块成为单迭代循环:

for b in 1..2 do
    puts b
    begin
        puts 'want this to run'
        break
        puts 'but not this'
    end while false
    puts 'also want this to run'
end

希望这有助于根据主题行在此登陆的下一位googler。


#2楼

如果您希望块返回有用的值(例如,在使用#map#inject等时),则nextbreak也要接受一个参数。

考虑以下:

def contrived_example(numbers)
  numbers.inject(0) do |count, x|
    if x % 3 == 0
      count + 2
    elsif x.odd?
      count + 1
    else 
      count
    end
  end
end

等价于next

def contrived_example(numbers)
  numbers.inject(0) do |count, x|
    next count if x.even?
    next (count + 2) if x % 3 == 0
    count + 1
  end
end

当然,您总是可以将所需的逻辑提取到方法中,并从您的代码块内部进行调用:

def contrived_example(numbers)
  numbers.inject(0) { |count, x| count + extracted_logic(x) }
end

def extracted_logic(x)
  return 0 if x.even?
  return 2 if x % 3 == 0
  1
end

#3楼

使用关键字next 。 如果您不想继续下一项,请使用break

当在块中使用next ,它将导致该块立即退出,将控制权返回给迭代器方法,该方法随后可以通过再次调用该块来开始新的迭代:

f.each do |line|              # Iterate over the lines in file f
  next if line[0,1] == "#"    # If this line is a comment, go to the next
  puts eval(line)
end

当在块中使用时, break将控制从块中移出,从调用该块的迭代器中移出,并转移到迭代器调用后的第一个表达式中:

f.each do |line|             # Iterate over the lines in file f
  break if line == "quit\n"  # If this break statement is executed...
  puts eval(line)
end
puts "Good bye"              # ...then control is transferred here

最后,在块中使用return

return总是导致封闭方法返回,而不管其在块中嵌套的深度如何(对于lambda除外):

def find(array, target)
  array.each_with_index do |element,index|
    return index if (element == target)  # return from find
  end
  nil  # If we didn't find the element, return nil
end

#4楼

使用关键字break而不是return


#5楼

也许您可以使用内置方法来查找数组中的特定项目,而不是each targets都可以手动完成。 一些例子:

class Array
  def first_frog
    detect {|i| i =~ /frog/ }
  end

  def last_frog
    select {|i| i =~ /frog/ }.last
  end
end

p ["dog", "cat", "godzilla", "dogfrog", "woot", "catfrog"].first_frog
# => "dogfrog"
p ["hats", "coats"].first_frog
# => nil
p ["houses", "frogcars", "bottles", "superfrogs"].last_frog
# => "superfrogs"

一个例子就是做这样的事情:

class Bar
  def do_things
    Foo.some_method(x) do |i|
      # only valid `targets` here, yay.
    end
  end
end

class Foo
  def self.failed
    @failed ||= []
  end

  def self.some_method(targets, &block)
    targets.reject {|t| t.do_something.bad? }.each(&block)
  end
end
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!