Ruby hat eine universelle Vorstellung von " Wahrhaftigkeit " und " Falschheit ".
Ruby hat zwei Klassen spezifische haben für Boolesche Objekte, TrueClass
und FalseClass
mit Instanzen Singleton durch die speziellen Variablen bezeichnet true
und false
sind.
Allerdings Truthiness und falsiness sind nicht auf Instanzen dieser beiden Klassen beschränkt, ist das Konzept universell und gilt für jedes einzelne Objekt in Ruby. Jedes Objekt ist entweder wahr oder falsch . Die Regeln sind sehr einfach. Insbesondere sind nur zwei Objekte falsch :
nil
, die Singleton-Instanz vonNilClass
undfalse
, die Singleton-Instanz vonFalseClass
Jedes andere Objekt ist wahr . Dies schließt auch Objekte ein, die in anderen Programmiersprachen als falsch gelten , wie z
Diese Regeln sind in die Sprache integriert und nicht benutzerdefinierbar. Es gibt keine to_bool
implizite Konvertierung oder ähnliches.
Hier ist ein Zitat aus der ISO Ruby-Sprachspezifikation :
6.6 Boolesche Werte
Ein Objekt wird entweder als wahres Objekt oder als falsches Objekt klassifiziert .
Nur falsch und null sind falsche Objekte. false ist die einzige Instanz der Klasse
FalseClass
(siehe 15.2.6), für die ein falscher Ausdruck ausgewertet wird (siehe 11.5.4.8.3). nil ist die einzige Instanz der KlasseNilClass
(siehe 15.2.4), für die ein nil-Ausdruck ausgewertet wird (siehe 11.5.4.8.2).Andere Objekte als false und nil werden in trueish-Objekte eingeteilt. true ist die einzige Instanz der Klasse
TrueClass
(siehe 15.2.5), für die ein true-Ausdruck ausgewertet wird (siehe 11.5.4.8.3).
Die ausführbare Datei Ruby / Spec scheint zuzustimmen :
it "considers a non-nil and non-boolean object in expression result as true" do if mock('x') 123 else 456 end.should == 123 end
Nach diesen beiden Quellen würde ich annehmen, dass Regexp
s auch wahr sind , aber nach meinen Tests sind sie nicht:
if // then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are falsy'
Ich habe dies auf YARV 2.7.0-Preview1 , TruffleRuby 19.2.0.1 und JRuby 9.2.8.0 getestet . Alle drei Implementierungen stimmen überein und stimmen nicht mit der ISO Ruby-Sprachspezifikation und meiner Interpretation der Ruby / Spec überein.
Etwas präziser, Regexp
Objekte, die das Ergebnis der Bewertung von Regexp
Literalen sind, falsch , während Regexp
Objekte, die das Ergebnis eines anderen Ausdrucks sind, wahr sind :
r = //
if r then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are truthy'
Ist das ein Fehler oder ein gewünschtes Verhalten?
Regex.new("a")
das wahr ist.!!//
ist falsch, aber!!/r/
wahr. Tatsächlich seltsam.!!/r/
produziertfalse
für mich mit (RVM) Ruby 2.4.1.//
inif // then
als Test (eine Abkürzung fürif //=~nil then
) interpretiert wird (das ist unabhängig vom Muster immer falsch) und nicht als Regexp-Instanz.Antworten:
Das ist kein Fehler. Was passiert ist, dass Ruby den Code so umschreibt, dass
effektiv wird
Wenn Sie diesen Code in einem normalen Skript ausführen (und das nicht verwenden)
-e
Option ), sollte eine Warnung angezeigt werden:Dies ist wahrscheinlich die meiste Zeit etwas verwirrend, weshalb die Warnung ausgegeben wird, kann aber für eine Zeile mit der
-e
Option nützlich sein . Beispielsweise können Sie alle Zeilen, die einem bestimmten regulären Ausdruck entsprechen, aus einer Datei mit drucken(Das Standardargument für
print
ist$_
ebenfalls.)quelle
-n
,-p
,-a
und-l
Optionen, sowie die wenige Kernel - Methoden , die nur verfügbar sind , wenn-n
oder-p
verwendet werden (chomp
,chop
,gsub
undsub
).NODE_LIT
mit TypT_REGEXP
. Diejenige, die Sie in Ihrer Antwort gepostet haben, bezieht sich auf ein dynamischesRegexp
Literal , dh einRegexp
Literal, das Interpolation verwendet, z/#{''}/
.$_
als Knoten hinzuzufügen , den der Compiler wie gewohnt behandelt, während im statischen Fall alles von der behandelt wird Compiler. Das ist eine Schande für mich, denn „Hey, du kannst sehen, wo der Analysebaum hier umgeschrieben wird“ ist eine nette Antwort.Dies ist das Ergebnis (soweit ich das beurteilen kann) eines undokumentierten Merkmals der Rubinsprache, das am besten durch diese Spezifikation erklärt wird :
Sie können im Allgemeinen denken,
$_
als die „letzte Zeichenfolge gelesen vongets
“Um die Sache noch verwirrender zu machen, ist
$_
(zusammen mit$-
) keine globale Variable; es hat lokalen Geltungsbereich .Wenn ein Ruby-Skript gestartet wird ,
$_ == nil
.Also der Code:
Wird interpretiert als:
... was Falsey zurückgibt.
Andererseits gilt für einen nicht wörtlichen regulären Ausdruck (z. B.
r = //
oderRegexp.new('')
) diese spezielle Interpretation nicht.//
ist wahr; genau wie alle anderen Objekte in Rubin nebennil
undfalse
.Sofern kein Ruby-Skript direkt in der Befehlszeile (dh mit dem
-e
Flag) ausgeführt wird, zeigt der Ruby-Parser eine Warnung vor einer solchen Verwendung an:Sie können dieses Verhalten in einem Skript verwenden, beispielsweise mit:
... Es wäre jedoch normaler, dem Ergebnis von eine lokale Variable zuzuweisen
gets
und die Regex-Prüfung explizit für diesen Wert durchzuführen.Mir ist kein Anwendungsfall für die Durchführung dieser Prüfung mit einem leeren regulären Ausdruck bekannt, insbesondere wenn dieser als Literalwert definiert ist. Das Ergebnis, das Sie hervorgehoben haben, würde in der Tat die meisten Ruby-Entwickler überraschen.
quelle
!// #=> true
hat das gleiche Verhalten und ist nicht in einer Bedingung. Ich konnte keinen booleschen Kontext finden (bedingt oder nicht), in dem er sich wie erwartet verhält.!// ? true : false
Retourentrue
? Ich denke, das ist wieder der gleiche Punkt - es wird interpretiert als:!(// =~ nil) ? true : false
$_ = 'hello world'
vor dem Ausführen des obigen Codes manuell festlegen , sollten Sie ein anderes Ergebnis erhalten - weil// =~ 'hello world'
, aber nicht übereinstimmtnil
.!//
ohne die bedingte Auswertung zutrue
. Bei der von Ihnen angegebenen Spezifikation handelt es sich um einRegexp
Literal in einer Bedingung. In diesem Beispiel gibt es jedoch keine Bedingung, sodass diese Spezifikation nicht gilt.puts !//; $_ = ''; puts !//
- Ich nehme an, weil der Parser es wie ein Makro erweitert; es muss nicht unbedingt in einer Bedingung sein?