Ответы:
Нет нет. Он используется для преобразования значения в логическое значение:
!!nil #=> false
!!"abc" #=> true
!!false #=> false
Обычно это не нужно использовать, поскольку единственными ложными значениями для Ruby являются nil
и false
, поэтому обычно лучше оставить это соглашение в силе.
Думайте об этом как
!(!some_val)
Одна вещь, для которой он используется на законных основаниях - это предотвращение возврата огромного куска данных. Например, вы, вероятно, не хотите возвращать 3 МБ данных изображения в вашем has_image?
методе, или вы не хотите возвращать весь пользовательский объект в logged_in?
методе. Использование !!
преобразует эти объекты в простой true
/ false
.
.nil?
вместо использования !!
? Есть ли разница?
!!true #=> true
иtrue.nil? #=> false
!
означает отрицание логического состояния, два !
s ничего особенного, кроме двойного отрицания.
!true == false
# => true
Обычно используется, чтобы заставить метод возвращать логическое значение. Он обнаружит любую правдивость, такую как строка, целые числа, а что нет, и превратит ее в логическое значение.
!"wtf"
# => false
!!"wtf"
# => true
Более реальный вариант использования:
def title
"I return a string."
end
def title_exists?
!!title
end
Это полезно, когда вы хотите убедиться, что логическое значение возвращается. ИМХО это вроде бессмысленно, хотя, видя , что оба , if 'some string'
и if true
точно такой же поток, но некоторые люди считают полезным явно возвращать логическое значение.
title
, можете также сделать самое близкое к этому ... Я полагаю
Обратите внимание, что эта идиома существует и в других языках программирования. C не имеет встроенного bool
типа, поэтому все логические значения были напечатаны как int
вместо, с каноническими значениями 0
или 1
. Возьмем этот пример (скобки добавлены для ясности):
!(1234) == 0
!(0) == 1
!(!(1234)) == 1
Синтаксис not-not преобразует любое ненулевое целое число 1
в каноническое логическое истинное значение.
В целом, однако, я считаю, что гораздо лучше провести разумное сравнение, чем использовать эту необычную идиому:
int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious
Это полезно, если вам нужно сделать эксклюзив или . Копирование ответа Мэтта Ван Хорна с небольшими изменениями:
1 ^ true
TypeError: can't convert true into Integer
!!1 ^ !!true
=> false
Я использовал его, чтобы убедиться, что две переменные либо равны нулю, либо обе не равны нулю.
raise "Inconsistency" if !!a ^ !!b
Это «двойной негатив», но практика не приветствуется. Если вы используете rubocop , вы увидите, что он жалуется на такой код с Style/DoubleNegation
нарушением.
В обоснование состояния:
Поскольку это так загадочно и обычно излишним, его следует избегать [тогда перефразирую:] Изменение
!!something
в!something.nil?
!!false # => false
пока!false.nil? # => true
!(foo.nil? || foo == false)
- более многословно, да, но менее загадочно.
Понимание того, как это работает, может быть полезно, если вам нужно преобразовать, скажем, перечисление в логическое значение. У меня есть код, который делает именно это, используя classy_enum
гем:
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
Тогда в сервисном коде у меня есть, например:
raise Application::Error unless !!object.link_status # => raises exception for "No" and "Denied" states.
Фактически оператор bangbang стал тем, что я мог бы написать как метод to_bool.