Respostas:
Não não. É usado para converter um valor em um booleano:
!!nil #=> false
!!"abc" #=> true
!!false #=> false
Geralmente, não é necessário usá-lo, já que os únicos valores falsos para Ruby são nil
e false
, portanto, geralmente é melhor deixar essa convenção permanecer.
Pense nisso como
!(!some_val)
Uma coisa para a qual ele é usado legitimamente é impedir que um grande pedaço de dados seja retornado. Por exemplo, você provavelmente não deseja retornar 3 MB de dados de imagem no seu has_image?
método, ou talvez não queira retornar todo o objeto do usuário no logged_in?
método. Usar !!
converte esses objetos em um simples true
/ false
.
.nil?
vez de usar !!
? Existe alguma diferença?
!!true #=> true
etrue.nil? #=> false
!
significa negar estado booleano, dois !
s não é nada de especial, exceto uma dupla negação.
!true == false
# => true
É comumente usado para forçar um método a retornar um booleano. Ele detectará qualquer tipo de veracidade, como string, números inteiros e o que não for, e o transformará em um booleano.
!"wtf"
# => false
!!"wtf"
# => true
Um caso de uso mais real:
def title
"I return a string."
end
def title_exists?
!!title
end
Isso é útil quando você deseja garantir que um booleano seja retornado. IMHO é meio inútil, porém, vendo que tanto if 'some string'
e if true
é exatamente o mesmo fluxo, mas algumas pessoas acham que é útil para retornar explicitamente um boolean.
title
, pode muito bem fazer a coisa mais próxima a ele ... suponho
Observe que esse idioma também existe em outras linguagens de programação. C não tinha um bool
tipo intrínseco ; portanto, todos os booleanos foram digitados int
, com valores canônicos de 0
ou 1
. Veja este exemplo (parênteses adicionados para maior clareza):
!(1234) == 0
!(0) == 1
!(!(1234)) == 1
A sintaxe "não-não" converte qualquer número inteiro diferente de zero em 1
, o valor verdadeiro booleano canônico.
Em geral, porém, acho muito melhor fazer uma comparação razoável do que usar esse idioma incomum:
int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious
É útil se você precisar fazer um exclusivo ou . Copiando da resposta de Matt Van Horn com pequenas modificações:
1 ^ true
TypeError: can't convert true into Integer
!!1 ^ !!true
=> false
Usei-o para garantir que duas variáveis fossem nulas ou nulas.
raise "Inconsistency" if !!a ^ !!b
É "duplo negativo", mas a prática está sendo desencorajada. Se você estiver usando rubocop , verá uma reclamação nesse código com uma Style/DoubleNegation
violação.
A lógica afirma:
Como isso é enigmático e geralmente redundante, deve ser evitado [depois parafraseando:] Altere
!!something
para!something.nil?
!!false # => false
enquanto!false.nil? # => true
!(foo.nil? || foo == false)
- mais detalhado, sim, mas menos enigmático.
Entender como funciona pode ser útil se você precisar converter, digamos, uma enumeração em um booleano. Eu tenho um código que faz exatamente isso, usando a classy_enum
gema:
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
Então, no código de serviço, tenho, por exemplo:
raise Application::Error unless !!object.link_status # => raises exception for "No" and "Denied" states.
Efetivamente, o operador bangbang se tornou o que eu poderia ter escrito como um método chamado to_bool.