Cosa fa !! intendi in rubino?


134

Mi chiedo solo cosa ci !!sia in Ruby.

Risposte:


161

Non non. È usato per convertire un valore in un valore booleano:

!!nil   #=> false
!!"abc" #=> true
!!false #=> false

Di solito non è necessario usarlo, dato che gli unici falsi valori di Ruby sono nile false, quindi di solito è meglio lasciar stare quella convenzione.

Pensalo come

!(!some_val)

Una cosa utilizzata per legittimamente è impedire la restituzione di un enorme blocco di dati. Ad esempio, probabilmente non vuoi restituire 3 MB di dati immagine nel tuo has_image?metodo, oppure potresti non voler restituire l'intero oggetto utente nel logged_in?metodo. L'utilizzo !!converte questi oggetti in un semplice true/ false.


8
Non è una cattiva pratica usarlo. Il doppio bang viene spesso usato nei predicati (metodi che terminano con?) Per restituire un valore esplicitamente booleano.
Swanand,

6
Alex, non devi preoccuparti di restituire oggetti di grandi dimensioni, poiché Ruby restituirà un riferimento, non una copia dell'oggetto.
DSimon

10
@DSimon, a volte è necessario preoccuparsi di oggetti di grandi dimensioni, come quando si stampa o si registra un valore durante il debug.
Wayne Conrad,

Perché non semplicemente tornare .nil?invece di usare !!? C'è una differenza?
ashes999,

3
C'è una differenza quando il tuo valore è un booelan. !!true #=> trueetrue.nil? #=> false
Alex Wayne,

31

Restituisce truese l'oggetto a destra non lo è nile non lo è false, falsese lo è nilofalse

def logged_in?   
  !!@current_user
end

1
Era ovvio che veniva da Restful_Auth ?! : D
Cameron,

14

!significa negare lo stato booleano, due !s non è niente di speciale, a parte una doppia negazione.

!true == false
# => true

È comunemente usato per forzare un metodo per restituire un valore booleano. Rileverà qualsiasi tipo di verità, come stringa, numeri interi e cosa no, e lo trasformerà in un valore booleano.

!"wtf"
# => false

!!"wtf"
# => true

Un caso d'uso più reale:

def title
  "I return a string."
end

def title_exists?
  !!title
end

Ciò è utile quando si desidera assicurarsi che venga restituito un valore booleano. IMHO è in qualche modo inutile, visto che entrambi if 'some string'ed if trueè esattamente lo stesso flusso, ma alcune persone trovano utile restituire esplicitamente un booleano.


mi sembra solo un modo più veloce rispetto all'utilizzo di un'istruzione if o di un operatore ternario. Dal momento che non puoi semplicemente tornare title, può anche fare la cosa più vicina ad esso ... Suppongo
Carson Myers,

6

Nota che questo linguaggio esiste anche in altri linguaggi di programmazione. C non aveva un booltipo intrinseco , quindi tutti i booleani venivano digitati come intinvece, con valori canonici di 0o 1. Fa questo esempio (parentesi aggiunte per maggiore chiarezza):

!(1234) == 0
!(0) == 1
!(!(1234)) == 1

La sintassi "non-no" converte qualsiasi numero intero diverso da zero in 1, il valore vero booleano canonico.

In generale, però, trovo molto meglio fare un confronto ragionevole piuttosto che usare questo linguaggio insolito:

int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious

O solo se (x). !! è utile quando è necessario ottenere 0/1. È possibile o meno prendere in considerazione (x)? 1: 0 più chiaro.
derobert,

3

È utile se devi fare un esclusivo o . Copia dalla risposta di Matt Van Horn con lievi modifiche:

1 ^ true
TypeError: can't convert true into Integer

!!1 ^ !!true
=> false

L'ho usato per assicurarmi che due variabili fossero entrambe nulle o entrambe non nulle.

raise "Inconsistency" if !!a ^ !!b

3

È "doppio negativo", ma la pratica viene scoraggiata. Se stai usando rubocop , lo vedrai lamentarti di tale codice con aStyle/DoubleNegation violazione.

La logica afferma:

Poiché questo è sia criptico che di solito ridondante, dovrebbe essere evitato [quindi parafrasando:] Passa !!somethinga!something.nil?


1
Ma ... !!false # => falsementre!false.nil? # => true
Doug

@Doug Se sai di avere un valore booleano, è ridondante (basta usare il valore). Se non lo fai, puoi usare !(foo.nil? || foo == false)- più prolisso, sì, ma meno criptico.
David Moles,

0

Comprendere come funziona può essere utile se è necessario convertire, per esempio, un elenco in un valore booleano. Ho un codice che fa esattamente questo, usando la classy_enumgemma:

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

Quindi nel codice di servizio ho, ad esempio:

raise Application::Error unless !!object.link_status   # => raises exception for "No" and "Denied" states.

In effetti l'operatore bangbang è diventato ciò che altrimenti avrei potuto scrivere come un metodo chiamato to_bool.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.