如何在调用者Proc中调用“break”?

时间:2014-10-29 23:24:29

标签: ruby-on-rails ruby

我正在编写一个迭代一个集合的库,并为集合中的每个项目调用调用者的proc。例如:

def self.each(&block)
    # ... load some data into results_array
    results_array.each do |result|
        status = block.call(result)
        # how do I know to call break if the user calls break?
        break if status == false
    end
end

目前,正如您在我的代码中所看到的,我检查了"最后评估的表达式"为了打破。这似乎容易出错,因为最终用户可能有一个完全正确的理由,他们的最后一个表达式评估为false。更合适的是使用" break"来检测呼叫者。

如果用户调用break,我怎么知道调用break?

2 个答案:

答案 0 :(得分:0)

这应该有效,除非我不明白你想要做什么:

def each(&block)
  # ... load some data into results_array
  results_array= [1, 2, 3]
  results_array.each do |result|
    block.call(result)
  end
end


each do |result|
  puts result
  break
end

答案 1 :(得分:0)

如果您使用yield代替block.call,则可以使用nextbreak之间的行为差​​异。举个例子:

def each(&block)
  puts "before"
  result = yield
  puts "after"

  result
end

each do
  puts "hello"
  next
end

# Result:
#   before
#   hello
#   after

each do
  puts "hello"
  break
end

# Result:
#   before
#   hello

如您所见,当您在块中使用next时,控件将返回给调用块的函数。但是,如果使用break,则调用函数将立即返回nil作为返回值。你现在可以通过一些技巧来利用这种行为:

def each(&block)
  # ...

  results_array.each do |result|
    block_result = yielder(result, &block) || {:status => :break, :value => nil}
    if block_result[:status] == :break
      # block has called break
      #...
    else
      # block has called either next or the block has finished normally
      #...
    end
  end
end

def yielder(*args, &block)
  value = yield *args
  {:status => :normal, :value => value}
end

这是有效的,因为yielder函数在nil调用block的情况下返回break或者具有状态和块的返回值的散列。因此,您可以区分有效结果(始终与nil不同)和始终为nil的异常结果。