Odpowiedzi:
Nie nie. Służy do konwersji wartości na boolean:
!!nil #=> false
!!"abc" #=> true
!!false #=> false
Zwykle nie jest to konieczne, ponieważ jedynymi fałszywymi wartościami dla Rubiego są nili false, więc zazwyczaj najlepiej jest pozostawić tę konwencję.
Pomyśl o tym jako
!(!some_val)
Jedną z rzeczy, do których jest legalnie używany, jest zapobieganie zwracaniu ogromnej ilości danych. Na przykład prawdopodobnie nie chcesz zwracać 3 MB danych obrazu w swojej has_image?metodzie lub możesz nie chcieć zwracać całego obiektu użytkownika w logged_in?metodzie. Użycie !!konwertuje te obiekty na proste true/ false.
.nil?zamiast używać !!? Czy jest jakaś różnica?
!!true #=> trueoraztrue.nil? #=> false
!oznacza zanegowanie stanu logicznego, dwa !s to nic specjalnego, poza podwójną negacją.
!true == false
# => true
Jest powszechnie używany, aby wymusić na metodzie zwrócenie wartości logicznej. Wykryje każdy rodzaj prawdziwości, taki jak ciąg, liczby całkowite i inne, i zamieni go na wartość logiczną.
!"wtf"
# => false
!!"wtf"
# => true
Bardziej realny przypadek użycia:
def title
"I return a string."
end
def title_exists?
!!title
end
Jest to przydatne, gdy chcesz się upewnić, że zwracana jest wartość logiczna. IMHO jest to trochę bezcelowe, biorąc pod uwagę, że oba if 'some string'i if truesą dokładnie tym samym przepływem, ale niektórzy ludzie uważają, że przydatne jest jawne zwrócenie wartości logicznej.
title, równie dobrze możesz zrobić najbliższą rzecz ... przypuszczam
Zauważ, że ten idiom istnieje również w innych językach programowania. C nie ma typu wewnętrznego bool, więc wszystkie wartości logiczne zostały wpisane jako intzamiast tego, z wartościami kanonicznymi 0lub 1. Przyjmuje ten przykład (dla przejrzystości dodano nawiasy):
!(1234) == 0
!(0) == 1
!(!(1234)) == 1
Składnia „not-not” konwertuje dowolną niezerową liczbę całkowitą 1na kanoniczną logiczną wartość true.
Ogólnie jednak uważam, że znacznie lepiej jest dokonać rozsądnego porównania niż użyć tego niecodziennego idiomu:
int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious
Jest to przydatne, jeśli chcesz zrobić ekskluzywną lub . Na podstawie odpowiedzi Matta Van Horna z niewielkimi modyfikacjami:
1 ^ true
TypeError: can't convert true into Integer
!!1 ^ !!true
=> false
Użyłem go, aby upewnić się, że dwie zmienne są albo zerowe, albo obie nie są zerowe.
raise "Inconsistency" if !!a ^ !!b
Jest to „podwójnie negatywne”, ale praktyka jest odradzana. Jeśli używasz rubocop , zobaczysz, że narzeka na taki kod z Style/DoubleNegationnaruszeniem.
W Uzasadnienie stanowi:
Ponieważ jest to zarówno tajemnicze, jak i zwykle zbędne, należy tego unikać [następnie parafrazując:] Zmień
!!somethingna!something.nil?
!!false # => falsepodczas gdy!false.nil? # => true
!(foo.nil? || foo == false)- bardziej rozwlekły, tak, ale mniej tajemniczy.
Zrozumienie, jak to działa, może być przydatne, jeśli chcesz przekonwertować, powiedzmy, wyliczenie na wartość logiczną. Mam kod, który robi dokładnie to, używając classy_enumklejnotu:
class LinkStatus < ClassyEnum::Base
def !
return true
end
end
class LinkStatus::No < LinkStatus
end
class LinkStatus::Claimed < LinkStatus
def !
return false
end
end
class LinkStatus::Confirmed < LinkStatus
def !
return false
end
end
class LinkStatus::Denied < LinkStatus
end
Wówczas w kodzie serwisowym mam np:
raise Application::Error unless !!object.link_status # => raises exception for "No" and "Denied" states.
W rzeczywistości operator bangbang stał się tym, co inaczej mógłbym napisać jako metodę o nazwie to_bool.