Réponses:
Pas pas. Il est utilisé pour convertir une valeur en booléen:
!!nil #=> false
!!"abc" #=> true
!!false #=> false
Il n'est généralement pas nécessaire de l'utiliser car les seules fausses valeurs de Ruby sont nil
et false
, il est donc généralement préférable de laisser cette convention en vigueur.
Pensez-y comme
!(!some_val)
Une chose à laquelle il est légitimement utilisé est d'empêcher le retour d'une énorme quantité de données. Par exemple, vous ne souhaitez probablement pas renvoyer 3 Mo de données d'image dans votre has_image?
méthode, ou vous ne souhaitez peut-être pas renvoyer l'intégralité de votre objet utilisateur dans la logged_in?
méthode. Utiliser !!
convertit ces objets en un simple true
/ false
.
.nil?
au lieu d'utiliser !!
? Y a-t-il une différence?
!!true #=> true
ettrue.nil? #=> false
!
signifie nier l'état booléen, deux !
s n'ont rien de spécial, à part une double négation.
!true == false
# => true
Il est couramment utilisé pour forcer une méthode à renvoyer un booléen. Il détectera tout type de véracité, comme une chaîne, des entiers et autres, et le transformera en booléen.
!"wtf"
# => false
!!"wtf"
# => true
Un cas d'utilisation plus réel:
def title
"I return a string."
end
def title_exists?
!!title
end
Ceci est utile lorsque vous voulez vous assurer qu'un booléen est renvoyé. IMHO, c'est un peu inutile, cependant, vu que les deux if 'some string'
et que if true
c'est exactement le même flux, mais certaines personnes trouvent utile de renvoyer explicitement un booléen.
title
, autant faire la chose la plus proche ... Je suppose
Notez que cet idiome existe également dans d'autres langages de programmation. C n'avait pas de bool
type intrinsèque , donc tous les booléens ont été typés comme à la int
place, avec des valeurs canoniques de 0
ou 1
. Prend cet exemple (parenthèses ajoutées pour plus de clarté):
!(1234) == 0
!(0) == 1
!(!(1234)) == 1
La syntaxe "not-not" convertit tout entier différent de zéro en 1
la valeur vraie booléenne canonique.
En général, cependant, je trouve beaucoup mieux de faire une comparaison raisonnable que d'utiliser cet idiome inhabituel:
int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious
C'est utile si vous avez besoin de faire un ou exclusif . Copie de la réponse de Matt Van Horn avec de légères modifications:
1 ^ true
TypeError: can't convert true into Integer
!!1 ^ !!true
=> false
Je l'ai utilisé pour m'assurer que deux variables étaient soit nulles, soit toutes deux non nulles.
raise "Inconsistency" if !!a ^ !!b
C'est "double négatif", mais la pratique est découragée. Si vous utilisez rubocop , vous le verrez se plaindre d'un tel code avec unStyle/DoubleNegation
violation.
La justification stipule:
Comme c'est à la fois cryptique et généralement redondant, il faut éviter [puis paraphraser:] Remplacer
!!something
par!something.nil?
!!false # => false
pendant que!false.nil? # => true
!(foo.nil? || foo == false)
- plus verbeux, oui, mais moins cryptique.
Comprendre comment cela fonctionne peut être utile si vous devez convertir, par exemple, une énumération en booléen. J'ai du code qui fait exactement cela, en utilisant le classy_enum
gem:
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
Ensuite, dans le code de service, j'ai, par exemple:
raise Application::Error unless !!object.link_status # => raises exception for "No" and "Denied" states.
En fait, l'opérateur bangbang est devenu ce que j'aurais pu autrement écrire comme une méthode appelée to_bool.