gpt4 book ai didi

ruby - 我可以在 Ruby 的 Proc 中使用顶层中断来中断循环吗?

转载 作者:数据小太阳 更新时间:2023-10-29 08:19:41 24 4
gpt4 key购买 nike

问题

  • 为什么 break 在 proc 中跳出三个循环一直到 puts 8?这很违反直觉。
  • 有没有办法让它跳出最内层的循环,即puts 6

代码

3.times do
puts "outer loop"
break_proc = proc { break }

puts 1
loop do
puts 2
loop do
puts 3
loop do
puts 4
break_proc.call
puts 5
end
puts 6
end
puts 7
end
puts 8
end
outer loop
1
2
3
4
8
outer loop
1
2
3
4
8
outer loop
1
2
3
4
8

最佳答案

长话短说

您看到的行为是尝试将 Proc 对象视为传递给 Kernel#eval 的代码片段的结果。 ,或者认为 Proc 内的顶层 break 与循环内的裸 break 关键字相同。提供了对该行为的解释,但真正的解决方案是避免做您正在做的事情。

Procs 携带上下文

Why does break within a proc jump out of three loops all the way to puts 8?

发生这种情况是因为 Proc对象包含 Binding到创建它的上下文,break keyword正在退出迭代器 block 并返回到它的调用上下文。具体来说,您要在此处的顶级循环中创建 Proc:

3.times do
puts "outer loop"
break_proc = proc { break }

人们可能会认为 Ruby 的 break 只是在调用它的任何地方退出一个循环,但它的行为比这更复杂,尤其是当你试图做一些奇怪的事情时,比如顶层 break在一个过程中。 break 的用例甚至包含在 The Ruby Programming Language 中,它说:

[A break] causes the block to return to its iterator and the iterator to return to the method that invoked it. Because procs work like blocks, we expect break to do the same thing in a proc. We can’t easily test this, however. When we create a proc with Proc.new, Proc.new is the iterator that break would return from. And by the time we can invoke the proc object, the iterator has already returned. So it never makes sense to have a top-level break statement in a proc created with Proc.new[.]

— David Flanagan and Yukihiro Matsumoto. The Ruby Programming Language (Kindle Locations 8185-8192). O'Reilly Media.

当您创建深度嵌套的循环,然后使用带有运行时绑定(bind)的对象将其复杂化时,结果并不总是您所期望的。您看到的行为不是错误,尽管在某些情况下它可能是错误的。如果您想要实现语义的原因而不是对您所看到的行为的解释,则必须询问语言设计者为什么它会这样。

打破循环

Is there a way to make it break out of the innermost loop, that is, to puts 6?

是的,但不是在 Proc 中使用 break用实际的内联 break 语句替换 Proc#call 可以达到您的预期,并且是“可能可行的最简单的事情”,但您也可以使用 throwcatch如果你想调整你的嵌套级别。例如:

3.times do
puts "outer loop"
break_proc = proc { throw :up }

puts 1
loop do
puts 2
loop do
puts 3
catch :up do
loop do
puts 4
break_proc.call
puts 5
end
end
puts 6
end
puts 7
end
puts 8
end

这将产生:

outer loop
1
2
3
4
6
3
4
6
3
4
6

并在第三个循环中无限循环,您在其中放置 3

因此,这将执行您要求的操作,但可能会或可能不会执行您想要的操作。如果有帮助,太好了!如果没有,如果您想找到更优雅的数据结构或将您的任务分解为一组协作对象,您可能想问一个包含一些真实数据和行为的单独问题。

关于ruby - 我可以在 Ruby 的 Proc 中使用顶层中断来中断循环吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39336426/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com