Was macht !! meine in rubin?

134

Ich frage mich nur, was !!in Ruby ist.

Cameron
quelle

Antworten:

161

Nicht nicht. Es wird verwendet, um einen Wert in einen Booleschen Wert umzuwandeln:

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

Es ist jedoch normalerweise nicht erforderlich, es zu verwenden, da die einzigen falschen Werte für Ruby nilund falsesind. Daher ist es normalerweise am besten, diese Konvention beizubehalten.

Betrachten Sie es als

!(!some_val)

Eine Sache, für die es zu Recht verwendet wird, ist die Verhinderung der Rückgabe eines großen Datenblocks. Beispielsweise möchten Sie wahrscheinlich nicht 3 MB Bilddaten in Ihrer has_image?Methode zurückgeben, oder Sie möchten möglicherweise nicht Ihr gesamtes Benutzerobjekt in der logged_in?Methode zurückgeben. Using !!konvertiert diese Objekte in ein einfaches true/ false.

Alex Wayne
quelle
8
Es ist keine schlechte Praxis, dies zu verwenden. Double Bang wird häufig in Prädikaten (Methoden, die mit? Endet) verwendet, um einen explizit booleschen Wert zurückzugeben.
Swanand
6
Alex, Sie müssen sich nicht wirklich um die Rückgabe großer Objekte kümmern, da Ruby eine Referenz zurückgibt, keine Kopie des Objekts.
DSimon
10
@DSimon, manchmal müssen Sie sich um große Objekte kümmern, beispielsweise beim Drucken oder Protokollieren eines Werts während des Debuggens.
Wayne Conrad
Warum nicht einfach zurückkehren .nil?anstatt zu benutzen !!? Ist da ein Unterschied?
Asche999
3
Es gibt einen Unterschied, wenn Ihr Wert ein Booelan ist. !!true #=> trueundtrue.nil? #=> false
Alex Wayne
31

Es wird zurückgegeben, truewenn das Objekt rechts nicht ist nilund nicht false, falsewenn es niloder istfalse

def logged_in?   
  !!@current_user
end
RichH
quelle
1
War es offensichtlich, dass es von Restful_Auth kam?! : D
Cameron
14

!bedeutet negieren booleschen Zustand, zwei !s ist nichts Besonderes, außer einer doppelten Negation.

!true == false
# => true

Es wird häufig verwendet, um eine Methode zu zwingen, einen Booleschen Wert zurückzugeben. Es erkennt jede Art von Wahrhaftigkeit, wie z. B. Zeichenfolge, Ganzzahlen und was nicht, und verwandelt sie in einen Booleschen Wert.

!"wtf"
# => false

!!"wtf"
# => true

Ein realistischerer Anwendungsfall:

def title
  "I return a string."
end

def title_exists?
  !!title
end

Dies ist nützlich, wenn Sie sicherstellen möchten, dass ein Boolescher Wert zurückgegeben wird. IMHO ist es irgendwie sinnlos zu sehen, dass beide if 'some string'und if truegenau der gleiche Fluss sind, aber einige Leute finden es nützlich, einen Booleschen Wert explizit zurückzugeben.

August Lilleaas
quelle
Es scheint mir nur ein schnellerer Weg zu sein als die Verwendung einer if-Anweisung oder eines ternären Operators. Da Sie nicht einfach zurückkehren können title, können Sie auch das nächste tun ... Ich nehme an
Carson Myers
6

Beachten Sie, dass diese Redewendung auch in anderen Programmiersprachen vorhanden ist. C hatte keinen intrinsischen boolTyp, daher wurden alle Booleschen intWerte stattdessen mit kanonischen Werten von 0oder eingegeben 1. Nimmt dieses Beispiel (zur Verdeutlichung Klammern hinzugefügt):

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

Die "Nicht-Nicht" -Syntax konvertiert jede Ganzzahl ungleich Null in 1 den kanonischen booleschen wahren Wert.

Im Allgemeinen finde ich es jedoch viel besser, einen vernünftigen Vergleich anzustellen, als diese ungewöhnliche Redewendung zu verwenden:

int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious
Tom
quelle
Oder nur wenn (x). !! ist nützlich, wenn Sie entweder 0/1 erhalten müssen. Sie können (x) in Betracht ziehen oder nicht? 1: 0 klarer.
Derobert
3

Es ist nützlich, wenn Sie ein exklusives oder tun müssen . Kopie von Matt Van Horns Antwort mit geringfügigen Änderungen:

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

!!1 ^ !!true
=> false

Ich habe es verwendet, um sicherzustellen, dass zwei Variablen entweder beide null oder beide nicht null sind.

raise "Inconsistency" if !!a ^ !!b
Andrew Grimm
quelle
3

Es ist "doppelt negativ", aber die Praxis wird entmutigt. Wenn Sie Rubocop verwenden , werden Sie feststellen , dass es sich bei einem solchen Code mit einem beschwertStyle/DoubleNegation Verstoß .

Die Begründung lautet:

Da dies sowohl kryptisch und in der Regel überflüssig ist, sollte es vermieden werden , [dann paraphrasieren:] Wechsel !!somethingzu!something.nil?

Micah Elliott
quelle
1
Aber ... !!false # => falsewährend!false.nil? # => true
Doug
@Doug Wenn Sie wissen, dass Sie einen booleschen Wert haben, ist dieser redundant (verwenden Sie einfach den Wert). Wenn Sie dies nicht tun, können Sie verwenden !(foo.nil? || foo == false)- ausführlicher, ja, aber weniger kryptisch.
David Moles
0

Zu verstehen, wie es funktioniert, kann hilfreich sein, wenn Sie beispielsweise eine Aufzählung in einen Booleschen Wert konvertieren müssen. Ich habe Code, der genau das mit dem classy_enumEdelstein macht:

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

Dann habe ich im Service-Code zum Beispiel:

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

Tatsächlich ist der Bangbang-Operator zu dem geworden, was ich sonst als Methode namens to_bool geschrieben hätte.

inopinatus
quelle