开发者

Is this a reasonable use for &&= in Ruby?

开发者 https://www.devze.com 2022-12-16 23:16 出处:网络
In SO question 2068165 one answer raised the ide开发者_StackOverflow社区a of using something like this:

In SO question 2068165 one answer raised the ide开发者_StackOverflow社区a of using something like this:

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

as a DRYer way of saying

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

where the params Hash would be coming from a (Rails/ActionView) form.

It's a kind of corollary to the well-known ||= idiom, setting the value if the LHS is not nil/false.

Is using &&= like this actually a recognised Ruby idiom that I've somehow missed or have I just forgotten a more commonly-used idiom? It is getting rather late...


It ought to be. If nothing else, params[:task] is only evaluated once when using the &&= form.

To clarify:

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

calls [](:task) on params twice, [](:completed_at) and []=(:completed_at) once each on params[:task].

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

calls [](:task) on params once, and its value is stashed away for both the [](:completed_at) and []=(:completed_at) calls.


Actual example describing what I'm trying to illustrate (based on Marc-Andre's example code; much thanks):

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"

Note that using the "expanded" form causes "get" to be printed out twice, but using the compact form causes it to only be printed once.


Using &&=, in the case of LHS is false, it is only being read once, but not being set. This should make it clearer ...

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

The result:

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

精彩评论

暂无评论...
验证码 换一张
取 消