2013-10-25 18 views
10

Si consideri il seguente frammento IRB da una sessione appena iniziato:Strano significato di || e || = in Ruby (2.0, 1.9.3, 1.7.4 JRuby)

irb:01> baz   # => NameError, baz is not defined 
irb:02> baz || baz = 0 # => NameError, baz is not defined 
irb:03> baz   # => nil 

baz era una variabile non definita e cercando di valutarla prodotto a NameError. Tuttavia, in qualche modo, dopo questa operazione, è stato definito baz e ha un valore di nil. Apparentemente, il valore nil è stato assegnato alla variabile baz anche se nessuno (esplicitamente) ha chiesto che fosse. C'è un motivo di linguaggio di base per cui questo comportamento è desiderabile?

Qual è la regola che spiega questo comportamento e altri costrutti simile confusione, come questi:

irb:04> true if foo   # => NameError 
irb:05> foo     # => NameError; name still undefined 
irb:06> foo = (true if foo) # => nil 
irb:07> foo     # => nil; name defined as nil 
irb:08> true || i = 0 || j = 2 # => i and j are nil; || appears nonlazy 
irb:09> raise || quux = 1  # => RuntimeError, quux is nil 
+3

In realtà non stai usando '|| =' in nessuno dei tuoi esempi, il titolo della domanda è un po 'ingannevole – nzifnab

+0

Ancora più strano: '>> spam # => NameError; >> spam || = "uova" # => "uova"; >> spam # => "uova" '. Incoerente. – iamnotmaynard

+0

possibile duplicato di [Confusione con l'operazione di assegnazione all'interno della fallacia \ 'se \" blocco] (http://stackoverflow.com/questions/15183576/confusion-with-the-assignment-operation-inside-the-fallacy-if -block) –

risposta

9

Non so se è auspicabile, ma deriva dal modo Rubino analizza il codice. Ogni volta che si dispone di una parte di codice che assegna una variabile locale, a tale variabile locale viene assegnato nil anche se tale parte di codice non viene valutata. Nella tua linea di codice 2:

baz || baz = 0 

il primo baz restituito un errore perché tale variabile è stato assegnato. Quindi l'assegnazione baz = 0 che segue è stato non valutato, ma ciononostante era analizzato, così nel contesto di seguire, una variabile locale baz stato creato, e viene inizializzato a nil.

Con il secondo blocco codice, foo non viene assegnato durante true if foo e foo. Dopodiché, foo = (true if foo) ha un'assegnazione a foo, quindi, anche se (true if foo) viene valutato prima dell'assunzione di foo, non viene generato un errore in tale riga.

+1

Devo cancellare il mio commento come hai risolto la tua risposta ;-) Ora è corretto, l'assegnazione a baz è ** non ** eseguita ma ogni volta che Ruby ** parser ** rileva un compito, alloca uno spazio per esso e imposta a 'nil'. –

+0

@DavidUnric Potresti aver avuto qualcosa da dire alla mia risposta come prima, ma ora, non credo che il tuo commento aggiunga informazioni oltre alla mia risposta. – sawa

Problemi correlati