短路Ruby`begin ... end`块的适当习语是什么?

Sas*_*lla 4 ruby memoization

我经常使用begin ... end块语法来记住Ruby方法:

$memo = {}
def calculate(something)
  $memo[something] ||= begin
    perform_calculation(something)
  end
end
Run Code Online (Sandbox Code Playgroud)

但是,这里有一个陷阱。如果我begin ... end通过保护子句从该块提早返回,则不会记录结果:

$memo = {}
def calculate(something)
  $memo[something] ||= begin
    return 'foo' if something == 'bar'
    perform_calculation(something)
  end
end
# does not memoize 'bar'; method will be run each time
Run Code Online (Sandbox Code Playgroud)

我可以通过避免以下return语句来避免这种情况:

$memo = {}
def calculate(something)
  $memo[something] ||= begin
    if something == 'bar'
      'foo'
    else
      perform_calculation(something)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这可行,但是我不喜欢它,因为:

  1. 很容易忘记return在这种情况下我不允许使用。
  2. 在许多情况下,它会使代码混乱,而不是与保护子句相对。

除了避免,还有更好的习惯用法return吗?

eik*_*iko 5

据我所知,begin ... end不能短路。您可以使用proc完全完成您要尝试执行的操作:

$memo = {}
def calculate(something)
  $memo[something] ||= -> do
    return 'foo' if something == 'bar'
    perform_calculation(something)
  end.call
end
Run Code Online (Sandbox Code Playgroud)

话虽这么说,我从未见过这样做,所以这当然不是惯用的。


kai*_*chn 4

我会添加另一层:

def calculate(something)
  $memo[something] ||= _calculate(something)
end

def _calculate(something)
  return if something == 'bar'
  perform_calculation(something) # or maybe inline this then
end
Run Code Online (Sandbox Code Playgroud)

这样做的另一个好处是为您提供了一个方法,您可以在任何时候想要确保获得新计算的结果时调用该方法。不过,我会花更多时间在方法命名上。