Ich suche nach einer prägnanten Möglichkeit, einen Wert zu überprüfen, um zu sehen, ob er null oder null ist. Zur Zeit mache ich so etwas wie:
if (!val || val == 0)
# Is nil or zero
end
Das scheint aber sehr ungeschickt zu sein.
Objekte haben ein nil? Methode .
if val.nil? || val == 0
[do something]
end
Oder für nur eine Anweisung:
[do something] if val.nil? || val == 0
Wenn Sie Methodennamen mit Fragezeichen am Ende wirklich mögen:
if val.nil? || val.zero?
# do stuff
end
Ihre Lösung ist gut, wie auch einige andere Lösungen.
Mit Ruby können Sie nach einer hübschen Methode suchen, um alles zu tun, wenn Sie nicht aufpassen.
Zunächst einmal denke ich, dass dies die präziseste Methode ist, die Sie für diesen speziellen Zustand prüfen können.
Zweitens ist dies ein Codegeruch, der auf einen möglichen Fehler in Ihrem Design hinweist. Im Allgemeinen sollten Null und Null nicht dasselbe bedeuten. Wenn möglich, sollten Sie versuchen, die Möglichkeit auszuschließen, dass val gleich Null ist, bevor Sie diesen Code schlagen, indem Sie dies entweder am Anfang der Methode oder durch einen anderen Mechanismus überprüfen.
Möglicherweise haben Sie einen absolut legitimen Grund, dies zu tun. In diesem Fall denke ich, dass Ihr Code gut ist, aber ich würde zumindest in Betracht ziehen, den Null-Check nach Möglichkeit zu beseitigen.
Ab Ruby 2.3.0 können Sie den sicheren Navigationsoperator (&.
) mit Numeric#nonzero?
kombinieren. &.
gibt nil
zurück, wenn die Instanz nil
war, und nonzero?
- wenn die Nummer 0
war:
unless val&.nonzero?
# Is nil or zero
end
Oder postfix:
do_something unless val&.nonzero?
Sie können die Object.nil verwenden? speziell auf null testen (und nicht zwischen falsch und null gefangen werden). Sie können eine Methode auch mit einem Affen-Patch in Object einfügen.
class Object
def nil_or_zero?
return (self.nil? or self == 0)
end
end
my_object = MyClass.new
my_object.nil_or_zero?
==> false
Dies wird nicht empfohlen, da Änderungen an Object für Kollegen schwer zu verfolgen sind und Ihren Code für andere möglicherweise unvorhersehbar machen.
nil.to_i gibt null zurück, daher mache ich das oft:
val.to_i.zero?
Sie erhalten jedoch eine Ausnahme, wenn val ein Objekt ist, das nicht auf #to_i antwortet.
Ich glaube, Ihr Code ist falsch. Es werden drei Werte getestet: nil
,false
und null. Dies liegt daran, dass der Ausdruck !val
für alle Werte gilt, die falsch sind. In Ruby heißt dies nil
und false
.
Das Beste, was ich jetzt finden kann, ist
if val == nil || val == 0
# do stuff
end
Was natürlich nicht sehr schlau ist, ist aber (sehr) klar.
Meine Lösung verwendet auch Verfeinerungen ohne die Bedingungen.
module Nothingness
refine Numeric do
alias_method :nothing?, :zero?
end
refine NilClass do
alias_method :nothing?, :nil?
end
end
using Nothingness
if val.nothing?
# Do something
end
Rails führt dies über Attribut-Abfragemethoden aus, wobei 0 und "" neben false und nil auch "false" ergeben.
if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation
Es hat jedoch seinen Anteil an Kritikern. http://www.joegrossberg.com/archives/002995.html
Um so idiomatisch wie möglich zu sein, würde ich das vorschlagen.
if val.nil? or val == 0
# Do something
end
Weil:
Der kürzeste und beste Weg sollte sein
if val&.>(0)
# do something
end
Für val&.>(0)
it wird null zurückgegeben, wenn val gleich null ist, da> im Grunde auch eine Methode ist, null ist in Ruby gleich false. Es gibt false zurück, wenn val == 0
.
Kurz und klar
[0, nil].include?(val)
Das ist sehr knapp:
if (val || 0) == 0
# Is nil, false, or zero.
end
Es funktioniert, solange es Ihnen nichts ausmacht, false
genauso zu behandeln wie nil
. In den Projekten, an denen ich gearbeitet habe, ist diese Unterscheidung nur gelegentlich von Bedeutung. Die restliche Zeit bevorzuge ich persönlich .nil?
und habe etwas kürzeren Code.
[ Update : Ich schreibe so etwas nicht mehr. Es funktioniert, ist aber zu kryptisch. Ich habe versucht, meine Missetaten zu korrigieren, indem ich die wenigen Orte, an denen ich es tat, veränderte.]
Ich habe übrigens .zero?
nicht verwendet, da dies eine Ausnahme auslöst, wenn val
beispielsweise ein String ist. Aber .zero?
wäre in Ordnung, wenn Sie wissen, dass dies nicht der Fall ist.
Anstatt eine Klasse mit Affen zu patchen, können Sie Verfeinerungen verwenden, die in Ruby 2.1 beginnen. Verfeinerungen ähneln dem Affen-Patching; Dadurch können Sie die Klasse ändern, die Änderung ist jedoch auf den Bereich beschränkt, in dem Sie sie verwenden möchten.
Dies ist zu viel, wenn Sie diese Überprüfung einmal durchführen möchten. Wenn Sie sich jedoch wiederholen, ist dies eine gute Alternative zum Affen-Patching.
module NilOrZero
refine Object do
def nil_or_zero?
nil? or zero?
end
end
end
using NilOrZero
class Car
def initialize(speed: 100)
puts speed.nil_or_zero?
end
end
car = Car.new # false
car = Car.new(speed: nil) # true
car = Car.new(speed: 0) # true
Verfeinerungen wurden geändert in der letzten Minute, um in die Datei aufgenommen zu werden. So haben frühere Beispiele dies gezeigt, was nicht funktionieren wird.
class Car
using NilOrZero
end
Sie können case
verwenden, wenn Sie möchten:
case val with nil, 0
# do stuff
end
Dann können Sie alles verwenden, was mit ===
funktioniert, was manchmal schön ist. Oder machen Sie so etwas:
not_valid = nil, 0
case val1 with *not_valid
# do stuff
end
#do other stuff
case val2 with *not_valid, false #Test for values that is nil, 0 or false
# do other other stuff
end
Es ist nicht gerade eine gute OOP, aber es ist sehr flexibel und funktioniert. Meine if
s enden normalerweise case
s.
Natürlich funktioniert auch Enum.any?
/Enum.include?
... wenn Sie wirklich kryptisch werden möchten:
if [0, nil].include? val
#do stuff
end
Das Richtige ist natürlich, eine Methode oder Funktion zu definieren. Wenn Sie mit vielen Werten dasselbe tun müssen, verwenden Sie eine Kombination dieser Nice-Iteratoren.
Dies ergibt für null und null den Wert true: nil.to_s.to_d == 0
unless (val || 0).zero?
# do stufff
end
Ich mag die Rails blank?
-Methode für diese Art von Dingen wirklich, aber es wird keine true
für 0
zurückgegeben. So können Sie Ihre Methode hinzufügen:
def nil_zero?
if respond_to?(:zero?)
zero?
else
!self
end
end
Und es wird geprüft, ob irgendein Wert Null oder 0 ist:
nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false
if val.nil_zero?
#...
end
Ich gehe damit um, indem ich ein "ist?" Methode, die ich dann auf verschiedenen Klassen unterschiedlich implementieren kann. Also für Array "ist?" bedeutet "Größe> 0"; für Fixnum bedeutet es "Selbst! = 0"; für String bedeutet es "self! = ''". NilClass definiert natürlich "ist?" als gerade Null zurückkehren.