【问题标题】:Break out of a begin/end block early尽早突破开始/结束块
【发布时间】:2019-09-08 04:20:52
【问题描述】:

我想要一种退出开始/结束块的方法,同时仍然分配其结果所分配给的变量。

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 只能在循环中工作。有什么东西在我的想法中起作用吗?

目前我可以做到但希望避免的方式:

  • 在开始块中分配变量并返回
  • 将开始块的剩余部分放入 if 语句中
  • 在开始块之前执行计算

似乎有很多关于打破障碍的相关问题,但我找不到能回答这个特定版本的问题(可能是因为不可能)。

【问题讨论】:

  • 我不明白你为什么没有得到 void value 异常 SyntaxError。当解析器无法确定如何分配值时会发生这种情况,这里是由return 语句引起的(即使它曾经是return "leaving early" if false)。这就是我在 v2.6.1 中得到的。您使用的是哪个 Ruby 版本?
  • @CarySwoveland 不错。如果您在退货后有一些东西,例如puts "finished" 或只是一些要退货的值,看起来它可以工作
  • 是的,但还是很奇怪。

标签: ruby memoization


【解决方案1】:

我认为,如果您将所有这些逻辑都放入自己的方法中,您将为自己省去很多麻烦:

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

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

【讨论】:

  • 这是一些很棒的见解。在这里使用另一种方法很有意义,但是可以选择使用匿名 proc 是一种有趣的可能性
  • 这是一个很好的建议,但它没有回答以下问题:“在 begin 块中是否有任何工作按照我的想法?”。
  • @CarySwoveland 我相信我已经含蓄地回答了这个问题,但这里是明确的答案:不,据我所知。
  • OP 在最近对该问题的评论中肯定地回答了该问题,尽管我们同意这不是好的编码习惯
  • @CarySwoveland 解决了 SyntaxError,但实际上并没有解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多