提前跳出begin/end块

16

我希望有一种方式可以在退出一个begin/end块时仍然给其结果分配一个变量。

def foo
  @foo ||= begin
    puts "running"

    return "leaving early" if true # would be some sort of calculation

    # Other calculations
  end
end

我希望发生的事情

> foo
running
=> leaving early
> foo
=> leaving early

实际上发生了什么

> foo
running
=> leaving early
> foo
running
=> leaving early

代码不起作用是因为return退出整个方法而没有设置@foo。在循环中使用breaknext只起作用。有什么办法可以让我在begin块中实现我想要的效果吗?

目前我能想到的方法,但希望避免:

  • 在begin块内赋值变量并返回
  • 将begin块的其余部分放在if语句中
  • 在begin块之前进行计算

似乎有很多关于跳出块的相关问题,但我找不到一个回答这个具体版本的(也许是因为不可能)。


我不明白为什么你没有收到“void value exception” SyntaxError。当解析器无法确定如何分配值时,就会出现这种情况,这是由于return语句引起的(即使它是return "leaving early" if false)。这是我在v2.6.1中得到的结果。你使用的是哪个Ruby版本? - Cary Swoveland
@CarySwoveland 很好的发现。看起来如果你在 return 后面加上一些东西,比如 puts "finished" 或者只是一些要返回的值,它就能正常工作了。 - Tom Prats
是的,但这仍然很奇怪。 - Cary Swoveland
2个回答

21

如果你将所有的逻辑放入自己的方法中,我认为你将会大大减少很多挣扎:

def foo
  @foo ||= compute_foo
end

def compute_foo
  puts "running"

  return "leaving early" if true # would be some sort of calculation

  # Other calculations
end

这样可以将计算与记忆分离,使其更易于测试和推理,并且这是Ruby和其他语言中相当常见的设计模式。

当然,有方法可以做到你所要求的。最明显的解决方案是立即调用匿名proc:

def foo
  @foo ||= (proc do
    puts "running"

    next "leaving early" if true # would be some sort of calculation

    # Other calculations
  end)[] # or .call or .()
end

但你肯定不会对自己或任何未来维护此代码的人有任何好处。


这是一些很棒的见解。在这里使用另一种方法非常有道理,但是有选择使用匿名过程是一个有趣的可能性。 - Tom Prats
2
这是一个好建议,但它并没有回答问题:“在begin块中是否有任何东西可以按照我想的方式工作?” - Cary Swoveland
@CarySwoveland 我相信我已经隐含地回答了这个问题,但是这里明确回答一下:不,据我所知没有。 - mwp
OP在最近的评论中肯定回答了那个问题,尽管我们认为这不是良好的编码实践。 - Cary Swoveland
@CarySwoveland 这解决了语法错误,但并没有真正解决问题。 - mwp
真的。我必须更加努力地改掉我的坏习惯,即没有全面考虑问题。 - Cary Swoveland

0
你可以使用loop do ... end结构来代替begin ... end
在这种情况下,你可以使用break <value>来从块中返回值。
def foo
  @foo ||= loop do
     puts "running"

     break "leaving early" if true # would be some sort of calculation

     # Other calculations
     break "leaving at the end"
  end
end

这将给您带来您所期望的结果。
> foo
running
=> leaving early
> foo
=> leaving early

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接