E 'possibile implementare il ?? operatore in Ruby?C# ?? operatore in Ruby?
a = nil
b = 1
x = a ?? b # x should == 1
x = b ?? 2 # x should == 1
E 'possibile implementare il ?? operatore in Ruby?C# ?? operatore in Ruby?
a = nil
b = 1
x = a ?? b # x should == 1
x = b ?? 2 # x should == 1
Siete alla ricerca di assegnazione condizionale:
a ||= b # Assign if a isn't already set
e || operatore
a = b || 2 # Assign if b is assigned, or assign 2
x = b || 2
It (??
in C#) si chiama l'operatore si fondono.
Questo non funzionerà, per i motivi che ho delineato nella mia risposta. Prova a impostare b su false nell'esempio. –
In Ruby, gli operatori booleani corto circuito (||
, &&
, and
e or
) non restituiscono true
o false
, ma piuttosto il primo operando che determina il risultato della intera espressione. Funziona, perché Ruby ha un'idea piuttosto semplice della verità. O meglio, ha un'idea piuttosto semplice di falsità: nil
è falso, e ovviamente false
è falso. Tutto il resto è vero.
Quindi, dal momento che ||
vale quando almeno un dei suoi operandi è vero, e gli operandi vengono valutati da sinistra a destra, ciò significa che i rendimenti a || b
a
, quando a
è vero. Ma quando a
è falso, il risultato dell'espressione dipende esclusivamente da b
e pertanto viene restituito .
Ciò significa che, poiché nil
è falso, è sufficiente utilizzare ||
anziché ??
per gli esempi forniti. (C'è anche la nifty a ||= b
dell'operatore, che tipo di opere come a || a = b
, ma non del tutto.)
tuttavia, che solo opere, perché non utilizzano Booleans nei tuoi esempi. Se si prevede di trattare con valori booleani, che non funziona:
b = false
x = b || 2 # x should be == false, but will be 2
In tal caso, si dovrà usare #nil?
, e un'espressione condizionale:
b = false
x = unless b.nil? then b else 2 end # x should be == 2
o utilizzando il condizionale ternario operatore:
b = false
x = b.nil? ? 2 : b # x should be == false
Se si vuole, si può avvolgere che in un bel metodo:
class Object
def _? b = nil
return self
end
end
class NilClass
def _? b = nil
return yield if block_given?
return b
end
end
b = false
x = b._? { 2 } # x should be == false
x = b._? 2 # x should be == false
Questo frammento carina portato a voi da polimorfismo, lezioni aperte e il fatto che nil
è in realtà un oggetto che rappresenta il nulla (a differenza, ad esempio, Java, dove null
è realtà nulla).
'a || = b' non è tanto" tipo di "' a || a = b', ma esattamente 'a = a || b'. Non è un compito condizionale, l'assegnazione avverrà sempre. – Theo
@Theo: questo è quello che dice la bozza attuale della ISO Ruby Language Specification, ma è sbagliato. MRI, YARV, JRuby, Rubinius, XRuby, MacRuby, IronRuby, Ruby.NET, MagLev, SmallRuby, tinyrb, RubyGoLightly e ogni altra implementazione Ruby mai creata, implementarla come assegnazione condizionale di cortocircuito. The Ruby Programming Language (scritto da Matz stesso), Programming Ruby e ogni altro libro di Ruby mai scritto lo documentano in quel modo. La suite di test RubySpec la verifica in questo modo. Diverse discussioni su StackOverflow e dozzine di discussioni su ruby-talk dicono così. Lo dice lo stesso Matz. –
Il link obbligatorio all'articolo di Peter Cooper: http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html –
C'è la gemma coalesce, che è il più vicino possibile.
nil || 5 # => 5
false || 5 # => 5 :(
false._? 5 # => false :)
Questo non funzionerà, per le ragioni che ho delineato nella mia risposta. Prova a impostare a a false nel primo esempio o b a false nel secondo esempio. –
corretto, @ JörgWMittag. Attenti alla verità/falsità! –
Inoltre sono abbastanza sicuro che non si possa ottenere un errore "impossibile assegnare a zero" con ??. Ma potresti scrivere un metodo ifNil su object e su NilClass per valutare un blocco come in smalltalk – Rivenfall