2009-06-04 22 views
35

Ist es möglich, das zu implementieren? Betreiber in Ruby?C# ?? Betreiber in Ruby?

a = nil 
b = 1 

x = a ?? b # x should == 1 
x = b ?? 2 # x should == 1 

Antwort

33

Sie suchen bedingte Zuweisung:

a ||= b # Assign if a isn't already set 

und die ||

Betreiber
a = b || 2 # Assign if b is assigned, or assign 2 
+9

Dies wird nicht funktionieren, aus den Gründen, die ich in meiner Antwort umrissen habe. Versuchen Sie, im ersten Beispiel "false" oder im zweiten Beispiel "b" auf "false" zu setzen. –

+0

Richtig, @ JörgWMittag. Vorsicht vor dem Truthy/Falsch! –

+0

Auch ich bin mir ziemlich sicher, dass Sie nicht bekommen können "Kann nicht zu Null zuweisen" Fehler mit ??. Aber du könntest eine Methode ifNil auf Objekt und auf NilClass schreiben, um einen Block wie in Smalltalk auszuwerten. – Rivenfall

5
x = b || 2 

It (?? in C#) wird der coalesce Operator genannt.

+2

Das funktioniert nicht, aus den Gründen, die ich in meiner Antwort dargelegt habe. Versuchen Sie im Beispiel b auf false zu setzen. –

46

In Ruby, die Kurzschlüssen Booleschen Operatoren (||, &&, and und or) nicht zurück true oder false, sondern der erste Operanden, die das Ergebnis des gesamten Ausdrucks bestimmt. Das funktioniert, weil Ruby eine ziemlich einfache Vorstellung von Wahrheit hat. Oder eher, es hat eine ziemlich einfache Vorstellung von Falschheit: nil ist falsch, und false ist offensichtlich falsch. Alles andere ist wahr.

Also, da || wahr ist, wenn mindestens eine seiner Operanden wahr ist, und Operanden werden von links nach rechts ausgewertet, bedeutet dies, dass a || b kehrt a, wenn a wahr ist. Aber wenn a falsch ist, dann ist das Ergebnis des Ausdrucks nur von b abhängig und somit wird b zurückgegeben.

Das bedeutet, dass, weil nil falsch ist, Sie || anstelle von ?? für die Beispiele verwenden können, die Sie gaben. (Es gibt auch den raffinierten a ||= b Operator, welche Art von Arbeiten wie a || a = b, aber nicht ganz.)

jedoch, dass nur funktioniert, weil Sie Boolesche Werte nicht in Ihrem Beispiel. Wenn Sie mit Boolesche Werte behandeln erwarten, wird das nicht funktionieren:

b = false 

x = b || 2 # x should be == false, but will be 2 

In diesem Fall werden Sie #nil? verwenden, und einen bedingten Ausdruck:

b = false 

x = unless b.nil? then b else 2 end # x should be == 2 

oder mit dem dreifach konditionalen Betreiber:

b = false 

x = b.nil? ? 2 : b # x should be == false 

Wenn Sie möchten, können Sie, dass bis in einem schönen Verfahren wickeln kann:

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 

Dieses nette Schnipsel Ihnen durch Polymorphismus, offene Klassen und die Tatsache gebracht, dass nildarstellt Nichts eigentlich ein Objekt ist (im Gegensatz zu, sagen wir, Java, wo null eigentlich nichts ist).

+0

'a || = b' ist nicht so sehr" irgendwie "' a || a = b ', aber genau' a = a || b'. Es ist keine bedingte Zuweisung, die Zuweisung wird immer passieren. – Theo

+5

@Theo: Das ist der aktuelle Entwurf der ISO Ruby Language Specification, aber das ist falsch. MRI-, YARV-, JRuby-, Rubinius-, XRuby-, MacRuby-, IronRuby-, Ruby.NET-, MagLev-, SmallRuby-, Tinyrb-, RubyGoLightly- und jede andere Ruby-Implementierung, die jemals erstellt wurde, implementieren sie als bedingte Kurzschließungszuweisung. Die Ruby Programming Language (selbst geschrieben von matz), Programming Ruby und jedes andere jemals geschriebene Ruby-Buch dokumentieren dies. Die RubySpec-Testsuite testet es auf diese Weise. Mehrere Diskussionen über StackOverflow und Dutzende von Diskussionen über Ruby-Talk sagen dies. Matz selbst sagt es. –

+0

Der obligatorische Link zum Artikel von Peter Cooper: http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html –

1

Da ist der coalesce Edelstein, der so nah ist, wie Sie bekommen werden.

nil || 5 # => 5 
false || 5 # => 5 :(
false._? 5 # => false :)