2009-06-04 9 views

Odpowiedz

33

Szukacie cesji warunkowej:

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

i || Operator

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

To nie zadziała, z powodów opisanych w mojej odpowiedzi. Spróbuj ustawić wartość false w pierwszym przykładzie lub b na false w drugim przykładzie. –

+0

Popraw, @ JörgWMittag. Strzeżcie się prawdy/falsey! –

+0

Jestem także pewien, że nie można uzyskać błędu "nie można przypisać do zera" z ??. Ale możesz napisać metodę, jeśli nie na obiekcie i na NilClass, aby ocenić blok, jak w smalltalk – Rivenfall

5
x = b || 2 

IT (?? C#) jest wywoływana przez operatora COALESCE.

+2

To nie zadziała, z powodów, które przedstawiłem w mojej odpowiedzi. Spróbuj ustawić b na false w przykładzie. –

46

W Ruby, gdy zwarcie operatory logiczne (||, &&, and i or) nie zwracają true lub false, ale pierwszy operand, który decyduje o wyniku całego wyrażenia. To działa, ponieważ Ruby ma raczej proste pojęcie o prawdzie. Lub raczej ma raczej prosty pomysł fałszu: nil jest fałszywy, i oczywiście false jest fałszywy. Wszystko inne jest prawdziwe.

Tak, ponieważ || jest prawdziwe, gdy co najmniej jeden jej argumentów jest prawdziwy, a argumenty są obliczane od lewej do prawej, oznacza to, że a || b powraca a, gdy a jest prawdą. Ale gdy a jest fałszywe, wynik wyrażenia jest wyłącznie zależny od b, a zatem zwracany jest b.

Oznacza to, że ponieważ nil jest fałszywe, można po prostu użyć || zamiast ?? dla podanych przykładów. (Istnieje również ładne a ||= b operator, jakiego rodzaju prac, takich jak a || a = b, ale nie całkiem.)

jednak, że tylko prace, bo nie używać wartości logicznych w swoich przykładach. Jeśli spodziewasz się radzić sobie z wartości logicznych, które nie będą działać:

b = false 

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

W takim przypadku trzeba będzie używać #nil? i wyrażenia warunkowe:

b = false 

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

lub używając trójoperandowy warunkowy operator:

b = false 

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

Jeśli chcesz, możesz owinąć że w miłym sposobem:

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 

Ten uroczy fragment przedstawia Państwu przez polimorfizm, otwartych klas oraz fakt, że nil jest rzeczywiście obiekt reprezentujący nicość (w przeciwieństwie do, powiedzmy, Jawa, gdzie nulljest właściwie nic).

+0

'a || = b' to nie tyle" rodzaj "' a || a = b', ale dokładnie 'a = a || b'. Nie jest to przydział warunkowy, zadanie zawsze się powiedzie. – Theo

+5

@ Theo: tak brzmi aktualny projekt specyfikacji języka Ruby ISO, ale jest to błędne. MRI, YARV, JRuby, Rubinius, XRuby, MacRuby, IronRuby, Ruby.NET, MagLev, SmallRuby, tinyrb, RubyGoLightly i wszystkie inne implementacje Ruby, jakie kiedykolwiek stworzono, implementują to jako warunkowe zadanie zwarcia. Ruby Programming Language (napisany wspólnie przez Matza), Programowanie Ruby i każda inna książka napisana przez Ruby dokumentuje to w ten sposób. Testy testowe RubySpec testują to w ten sposób. Kilka dyskusji na temat StackOverflow i dziesiątek dyskusji na temat ruby-talk mówi tak. Sam Matz tak mówi. –

+0

Obligatoryjny link do artykułu Petera Coopera: http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html –

1

Istnieje klejnot coalesce, który jest tak blisko, jak to tylko możliwe.

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