【问题标题】:Is this a reasonable use for &&= in Ruby?这是 &&= 在 Ruby 中的合理使用吗?
【发布时间】:2011-01-05 07:56:26
【问题描述】:

SO question 2068165 中,一个答案提出了使用类似这样的想法:

params[:task][:completed_at] &&= Time.parse(params[:task][:completed_at])

作为 DRYer 的说法

params[:task][:completed_at] = Time.parse(params[:task][:completed_at]) if params[:task][:completed_at]

params Hash 来自 (Rails/ActionView) 表单的位置。

这是众所周知的||= 成语的一种推论,如果 LHS 为 not nil/false,则设置该值。

像这样使用&&= 实际上是一个公认的Ruby 习语,我不知何故错过了,或者我只是忘记了一个更常用的习语? 现在有点晚了……

【问题讨论】:

  • 解析器做了一些奇怪的事情:a = 1 如果 a 工作 和 b = 1 如果永远 fails
  • 如果是 xxx 的话要雪上加霜; xxx=1;结束失败

标签: ruby operators


【解决方案1】:

应该是的。如果不出意外,params[:task] 仅在使用 &&= 表单时计算一次。

澄清一下:

params[:task][:completed_at] = params[:task][:completed_at] && ...

params 上调用[](:task) 两次,[](:completed_at)[]=(:completed_at)params[:task] 上各调用一次。

params[:task][:completed_at] &&= ...

params 上调用[](:task) 一次,它的值被隐藏起来用于[](:completed_at)[]=(:completed_at) 调用。


描述我试图说明的实际示例(基于 Marc-Andre 的示例代码;非常感谢):

class X
  def get
    puts "get"
    @hash ||= {}
  end
end

irb(main):008:0> x = X.new
=> #<X:0x7f43c496b130>
irb(main):009:0> x.get
get
=> {}
irb(main):010:0> x.get[:foo] = 'foo'
get
=> "foo"
irb(main):011:0> x.get[:foo]
get
=> "foo"
irb(main):012:0> x.get[:foo] &&= 'bar'
get
=> "bar"
irb(main):013:0> x.get[:foo] = x.get[:foo] && 'bar'
get
get
=> "bar"

请注意,使用“扩展”表单会导致“get”被打印两次,但使用紧凑表单会导致它仅被打印一次。

【讨论】:

  • 你的答案不正确。两种形式是等效的,并且 params[:task][:completed_at] 被评估两次(假设它是真实的)(见我的回答)。
  • 我想我需要澄清一下我到底在回答什么。 :-P
  • 我希望你是对的,但是不,[:task] getter 在 &&= 形式中的执行次数也与 'if' 形式相同。我已经更新了我的答案以显示这一点。
  • 我将更新我的答案以展示我的反例,因为我认为您更新的答案仍在回答与我正在回答的问题不同的问题。 :-)
  • 顺便说一句:我不是指Time.parse(params[:task][:completed_at]) 函数调用;当然,这会产生额外的访问权限。我只是比较了&amp;&amp;= 表单与= ... &amp;&amp; ... 表单的访问次数。
【解决方案2】:

使用&amp;&amp;=,在LHS为false的情况下,只读取一次,不设置。这应该更清楚......

class Test
  def initialize(value)
    @v = value
  end
  def v=(value)
    puts "set"
    @v = value
  end
  def v
    puts "get=>#{@v}"
    @v
  end
end
t = Test.new(true)

t.v = t.v && true
puts '----'

t.v &&= true
puts '----'

t = Test.new(false) # lets make LHS false
t.v = t.v && true
puts '----'

t = Test.new(false) # lets make LHS false
t.v &&= true

结果:

get=>true
set
----
get=>true
set
----
get=>false
set
----
get=>false

【讨论】:

  • 当 LHS 为 false 时,这很好:如果它不存在,我们不想设置它,但如果它存在但不是我们真正的形式,我们可能需要转换/验证/解析它想要,例如我们将日期/时间作为字符串获取,并希望将其传递给模型所期望的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 2010-09-07
  • 2015-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多