Meilleur idiome de ruby ??pour "nul ou nul"
-
03-07-2019 - |
Question
Je cherche un moyen concis de vérifier une valeur pour savoir si elle est nulle ou nulle. Actuellement, je fais quelque chose comme:
if (!val || val == 0)
# Is nil or zero
end
Mais cela semble très maladroit.
La solution
Les objets ont un nil? méthode .
if val.nil? || val == 0
[do something]
end
Ou, pour une seule instruction:
[do something] if val.nil? || val == 0
Autres conseils
Si vous aimez vraiment les noms de méthodes avec des points d'interrogation à la fin:
if val.nil? || val.zero?
# do stuff
end
Votre solution est satisfaisante, de même que quelques-unes des autres solutions.
Ruby peut vous aider à faire tout ce que vous voulez, si vous ne faites pas attention.
Tout d’abord, je pense que c’est à peu près la façon la plus concise de vérifier cette condition particulière.
Deuxièmement, c’est une odeur de code qui indique une faille potentielle dans votre conception. Généralement, zéro et zéro ne devraient pas signifier la même chose. Si possible, essayez d’éliminer la possibilité que val soit nul avant de frapper ce code, en vérifiant cela au début de la méthode ou par un autre mécanisme.
Vous avez peut-être une raison tout à fait légitime de le faire, auquel cas je pense que votre code est bon, mais au moins, je penserais à essayer de supprimer le chèque nul si possible.
À partir de Ruby 2.3.0, vous pouvez associer l'opérateur de navigation sécurisée ( & amp;.
) à Numérique # non nul?
. & amp;.
renvoie nil
si l'instance était nil
et non nul?
- si le nombre était 0
:
unless val&.nonzero?
# Is nil or zero
end
Ou postfixe:
do_something unless val&.nonzero?
Vous pouvez utiliser Object.nil? tester spécifiquement pour zéro (et ne pas se laisser prendre entre faux et zéro). Vous pouvez aussi monkey-patcher une méthode dans Object.
class Object
def nil_or_zero?
return (self.nil? or self == 0)
end
end
my_object = MyClass.new
my_object.nil_or_zero?
==> false
Cela n'est pas recommandé car il est difficile pour les collègues de suivre les modifications apportées à Object et peut rendre votre code imprévisible pour les autres.
Je pense que votre code est incorrect. il testera en fait trois valeurs: nil
, false
et zéro. En effet, l'expression ! Val
est vraie pour toutes les valeurs fausses, lesquelles dans Ruby sont nil
et false
.
Le mieux que je puisse trouver en ce moment est
if val == nil || val == 0
# do stuff
end
Ce qui, bien sûr, n’est pas très intelligent, mais très clair.
nil.to_i renvoie zéro, je le fais souvent ainsi:
val.to_i.zero?
Cependant, vous obtiendrez une exception si val est un objet qui ne répond pas_à #to_i.
Ma solution utilise également les raffinements, moins les conditions.
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 le fait via des méthodes de requête attributaires, où en plus de false et nil, 0 et """ évaluer aussi à faux.
if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation
Cependant, il a sa part de détracteurs. http://www.joegrossberg.com/archives/002995.html
Pour être aussi idiomatique que possible, je suggérerais ceci.
if val.nil? or val == 0
# Do something
end
Parce que:
- Il utilise le zéro? méthode.
- Il utilise les options " ou " opérateur, ce qui est préférable à ||.
- Il n'utilise pas de parenthèses, ce qui n'est pas nécessaire dans ce cas. Les parenthèses ne doivent être utilisées que lorsqu'elles servent à quelque chose, par exemple, remplacer la priorité de certains opérateurs.
Le moyen le plus court et le meilleur devrait être
if val&.>(0)
# do something
end
Pour , val & amp;. > (0)
il ne retourne rien lorsque val est nul puisque > est fondamentalement aussi une méthode, nulle égale à false en rubis. Il renvoie false lorsque val == 0
.
Court et clair
[0, nil] .include? (val)
Je résous ce problème en définissant un "est?" méthode, que je peux ensuite mettre en œuvre différemment sur différentes classes. Donc pour Array, "is?" signifie "taille > 0"; pour Fixnum, cela signifie "self! = 0"; pour String, cela signifie "self! = ''". NilClass, bien sûr, définit "is". comme revenant à zéro.
Vous pouvez utiliser case
si vous aimez:
case val with nil, 0
# do stuff
end
Ensuite, vous pouvez utiliser tout ce qui fonctionne avec ===
, ce qui est bien parfois. Ou faire quelque chose comme ça:
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
Ce n’est pas vraiment une bonne POO, mais c’est très flexible et ça marche. Mes if
se retrouvent généralement sous la forme
Bien sûr, Enum.any?
/ Enum.include?
fonctionne aussi ... si vous voulez être vraiment crypté:
if [0, nil].include? val
#do stuff
end
La bonne chose à faire est bien sûr de définir une méthode ou une fonction. Ou, si vous devez faire la même chose avec beaucoup de valeurs, utilisez une combinaison de ces bons itérateurs.
J'aime beaucoup la méthode Rails blank?
pour ce genre de choses, mais elle ne renverra pas true
pour 0
. Vous pouvez donc ajouter votre méthode:
def nil_zero?
if respond_to?(:zero?)
zero?
else
!self
end
end
Et il vérifiera si une valeur est nulle ou 0:
nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false
if val.nil_zero?
#...
end
Au lieu de patcher une classe, vous pourriez utiliser améliorations à partir de Ruby 2.1. Les raffinements sont similaires à la correction de singe; en cela, ils vous permettent de modifier la classe, mais la modification est limitée à la portée dans laquelle vous souhaitez l'utiliser.
C’est excessif si vous voulez effectuer cette vérification une fois, mais si vous vous répétez, c’est une excellente alternative au patchage des singes.
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
Les modifications ont été modifiées à la dernière minute pour être intégrées au fichier. Ainsi, des exemples précédents peuvent avoir montré cela, ce qui ne fonctionnera pas.
class Car
using NilOrZero
end
C’est très concis:
if (val || 0) == 0
# Is nil, false, or zero.
end
Cela fonctionne tant que cela ne vous dérange pas de traiter false
de la même manière que nil
. Dans les projets sur lesquels j'ai travaillé, cette distinction n'a d'importance que de temps en temps. Le reste du temps, je préfère personnellement ignorer .nil?
et obtenir un code légèrement plus court.
[ Mettre à jour : je n'écris plus ce genre de chose. Cela fonctionne mais est trop cryptique. J'ai essayé de corriger mes méfaits en changeant les quelques endroits où je les ai faits.]
En passant, je n'ai pas utilisé .zero?
, car cela soulève une exception si val
est, par exemple, une chaîne. Mais .zero?
conviendrait si vous savez que ce n'est pas le cas.
Ceci vaut true pour nil et zéro: nil.to_s.to_d == 0
unless (val || 0).zero?
# do stufff
end
Une autre solution:
if val.to_i == 0
# do stuff
end
val ||= 0
if val == 0
# do something here
end