O que !! significa em rubi?


134

Apenas imaginando o que !!há em Ruby.

Respostas:


161

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 nile 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.


8
Não é uma prática ruim usar isso. Double bang é frequentemente usado em predicados (métodos que terminam com?) Para retornar um valor booleano explicitamente.
Swanand

6
Alex, você realmente não precisa se preocupar em retornar objetos grandes, pois Ruby retornará uma referência, não uma cópia do objeto.
DSimon

10
@DSimon, às vezes você precisa se preocupar com objetos grandes, como ao imprimir ou registrar um valor durante a depuração.
Wayne Conrad

Por que não apenas retornar em .nil?vez de usar !!? Existe alguma diferença?
precisa saber é o seguinte

3
Há uma diferença quando seu valor é um booelan. !!true #=> trueetrue.nil? #=> false
Alex Wayne

31

Retorna truese o objeto à direita não é nile não false, falsese é nilou nãofalse

def logged_in?   
  !!@current_user
end

1
Era óbvio que veio de Restful_Auth ?! : D
Cameron

14

!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.


parece-me apenas uma maneira mais rápida do que usar uma instrução if ou um operador ternário. Desde que você não pode simplesmente voltar title, pode muito bem fazer a coisa mais próxima a ele ... suponho
Carson Myers

6

Observe que esse idioma também existe em outras linguagens de programação. C não tinha um booltipo intrínseco ; portanto, todos os booleanos foram digitados int, com valores canônicos de 0ou 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

Ou apenas se (x). !! é útil quando você precisa obter 0/1. Você pode ou não considerar (x)? 1: 0 mais claro.
derobert

3

É ú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

3

É "duplo negativo", mas a prática está sendo desencorajada. Se você estiver usando rubocop , verá uma reclamação nesse código com uma Style/DoubleNegationviolação.

A lógica afirma:

Como isso é enigmático e geralmente redundante, deve ser evitado [depois parafraseando:] Altere !!somethingpara!something.nil?


1
Mas ... !!false # => falseenquanto!false.nil? # => true
Doug

@ Doug Se você sabe que possui um valor booleano, é redundante (basta usar o valor). Caso contrário, você pode usar !(foo.nil? || foo == false)- mais detalhado, sim, mas menos enigmático.
David Moles

0

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_enumgema:

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.