2010-01-15 11 views
7

In SO question 2068165 una risposta sollevato l'idea di usare qualcosa di simile:È un uso ragionevole per && = in Ruby?

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

come un modo essiccatore di dire

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

dove l'hash params sarebbe proveniente da un formulario (Rails/ActionView) .

È una sorta di corollario del noto linguaggio ||=, che imposta il valore se l'LHS è non nil/falso.

Si sta utilizzando &&= come questo in realtà un riconosciuto linguaggio Ruby che in qualche modo ho perso o che ho appena dimenticato un idioma più comunemente usato? È è ottenere piuttosto tardi ...

+0

Il parser fa alcune cose strane: a = 1 se funziona un ** ** e b = 1 se mai ** fallisce ** –

+0

per aggiungere la beffa al danno se xxx; xxx = 1; fine ** non riesce ** –

risposta

5

Dovrebbe essere. Se non altro, params[:task] viene valutato solo una volta quando si utilizza il modulo &&=.

per chiarire:

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

chiamate [](:task) su params due volte, [](:completed_at) e []=(:completed_at) una volta su params[:task].

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

invita [](:task) su params volta, e il suo valore è nascosto via per entrambe le [](:completed_at) e []=(:completed_at) chiamate.


esempio reale che descrive quello che sto cercando di illustrare (basato sul codice di esempio di Marc-Andre, molto grazie):

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" 

Si noti che utilizzando il modulo "esteso" causa "get" per essere stampato due volte, ma utilizzando la forma compatta fa sì che venga stampato una sola volta.

+0

La tua risposta è errata. Entrambe le forme sono equivalenti e params [: task] [: completed_at] viene valutato due volte (assumendo che sia veritiero) (vedi la mia risposta). –

+0

Penso di aver bisogno di chiarire cosa esattamente sto rispondendo. :-P –

+0

In qualche modo vorrei che tu avessi ragione, ma no, il getter [: task] verrà eseguito anche tante volte nel modulo && = come 'if'. Ho aggiornato la mia risposta per mostrarlo. –

1

L'utilizzo di &&=, nel caso di LHS è falso, viene letto solo una volta, ma non viene impostato. Questo dovrebbe rendere più chiaro ...

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 

Il risultato:

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

Quando LHS è falso, va bene: non vogliamo impostarlo se non c'è, ma potremmo aver bisogno di convertirlo/validarlo/analizzarlo se è presente ma non nella forma che vogliamo veramente, ad es. dove otteniamo una data/ora come una stringa e vogliamo passarla a un modello nel tipo che si aspetta. –

Problemi correlati