我正在编写一个迭代一个集合的库,并为集合中的每个项目调用调用者的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?
答案 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
,则可以使用next
和break
之间的行为差异。举个例子:
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
的异常结果。