【问题标题】:What is use of ||= begin....end block in Ruby?Ruby 中 ||= begin....end 块的用途是什么?
【发布时间】:2016-04-10 06:16:28
【问题描述】:

这两个代码sn-ps有什么区别:

   def config
    @config ||= begin
      if config_exists?  
        @config = return some value
      else
        {}
      end
    end
  end

  def config
    @config ||= method
  end

  def method
    if config_exists?
      return some value
    else
      {}
    end
  end

我对“begin ... end”块感到困惑。它对输出有什么影响吗?如果不是,那么这里的 begin ... end 块有什么用?

【问题讨论】:

  • 内部赋值(@config = )是多余的。
  • @config = return some value 似乎不是有效的 ruby​​ - 如果你能修复你的代码,那会有所帮助。

标签: ruby-on-rails ruby


【解决方案1】:

唯一会发生不同的事情是如果引发异常。例如,假设config_exists? 方法调用存在问题。如果它在第一个示例中引发异常,您的 @config 变量将设置为 {}。在第二个示例中,如果发生同样的事情,您的程序将崩溃。

附带说明,这里不需要return 关键字。实际上,该示例应如下所示。这是假设我理解意图。

def config
  @config ||= 
    begin
      if config_exists?    
        some_value
      else
        {}
      end
    rescue
      {}
    end
end

def config
  @config ||= method
end

def method
  if config_exists?
    some_value
  else
    {}
  end
end

两个示例完全相同,除非在第一个示例中引发异常 @config 仍将设置为 = some_value

另外,应该注意的是,如果@config 已经有值,则不会发生任何事情。 ||= 运算符等同于:

@config = some_value if @config.nil?

仅当变量当前为 nil 时才将其设置为此值。

希望这会有所帮助,并且我正确理解了您的问题。

【讨论】:

  • 这不是真的 - 两个代码块是相同的。
  • 也许我在这里遗漏了一些东西,但 beginrescue 关键字用于处理异常。如果config_exists?some_value引发异常,第二种情况如何处理?
  • 您错过了def 在异常处理方面的功能等同于begin 的事实。此外,由于这些示例都没有包含 rescue 块 - 如果引发异常,则不会有任何好处。
  • 我想他的例子缺少rescue。我只是假设这是故意的。否则就不需要beginend。也许这就是你要表达的意思。
  • 你可以循环使用它begin ... end while conditional
【解决方案2】:

首先,您需要知道定义的方法固有地包含begin ... end 块的功能。

在异常处理的上下文中,def method_name ... end 在功能上等同于begin ... end。例如,两者都可以包含rescue 语句。

您共享的两个代码块实际上是相同的,一个比另一个没有任何好处...除非您的method 需要在多个地方。在这种情况下,您可以通过将逻辑放入单个方法并从多个其他地方调用它来干掉您的代码。

【讨论】:

    【解决方案3】:

    在您的情况下,您甚至可以省略 begin ... end 块:

    @config ||=
      if config_exists?  
        return_some_value
      else
        {}
      end
    

    或者,使用ternary if

    @config ||= config_exists? ? return_some_value : {}
    

    对输出有影响吗?

    可以有所作为,因为与def ... end 不同,begin ... end 块不会创建新的变量范围。

    这是一个人为的例子:

    def foo
      a = 456  # doesn't affect the other a
    end
    
    a = 123
    b = foo
    
    p a: a, b: b #=> {:a=>123, :b=>456}
    

    对比:

    a = 123
    b = begin
      a = 456  # overwrites a
    end
    
    p a: a, b: b #=> {:a=>456, :b=>456}
    

    【讨论】:

      【解决方案4】:

      使用||= begin...end 允许您memoizebegin...end 中运行的任何结果。这对于缓存资源密集型计算的结果很有用。

      【讨论】:

      • 1.更准确地说,@variable ||= code 允许您缓存资源密集型计算。 2. 但是,begin ... end 允许您缓存由多个语句(“多行语句”)组成的表达式的结果。
      • 如果你想编辑你的答案,我可以删除我的 cmets。
      猜你喜欢
      • 1970-01-01
      • 2017-08-13
      • 2012-02-05
      • 2013-12-06
      • 2020-10-14
      • 2011-02-15
      相关资源
      最近更新 更多