web-dev-qa-db-fra.com

Meilleur idiome Ruby pour "nul ou nul"

Je cherche un moyen concis de vérifier une valeur pour voir 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.

71
csexton

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
65
Christian Lescuyer

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.

31
MilesZS

Tout d'abord, je pense que c'est à peu près le moyen le plus concis de vérifier cette condition particulière.

Deuxièmement, pour moi, il s’agit d’une odeur de code qui indique une faille potentielle dans votre conception. En règle générale, zéro et zéro ne doivent pas signifier la même chose. Si possible, essayez d’éliminer la possibilité que val soit nul avant de frapper ce code, soit en vérifiant cela au début de la méthode, soit en utilisant un autre mécanisme.

Vous avez peut-être une raison tout à fait légitime de faire cela, auquel cas je pense que votre code est bon, mais au moins, je penserais à essayer de supprimer si possible le chèque nul.

29
Mike Deck

À partir de Ruby 2.3.0, vous pouvez combiner l'opérateur de navigation sécurisée (&.) avec Numeric#nonzero? . &. renvoie nil si l'instance était nil et nonzero? - si le nombre était 0:

unless val&.nonzero?
  # Is nil or zero
end

Ou postfix:

do_something unless val&.nonzero?
23
ndnenkov

Vous pouvez utiliser Object.nil? tester spécifiquement pour néant (et ne pas se laisser prendre entre faux et néant). 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 les modifications apportées à Object sont difficiles à retracer pour vos collègues et peuvent rendre votre code imprévisible pour les autres.

9
Adrian Dunston

nil.to_i renvoie zéro, je fais donc souvent ceci:

val.to_i.zero?

Cependant, vous obtiendrez une exception si val est un objet qui ne répond pas à #to_i.

5
ntl

Je crois que votre code est incorrect. il testera en fait trois valeurs: nil,false, et zéro. Cela est dû au fait que l'expression !val est true pour toutes les valeurs false, qui 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.

4
unwind

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
3
RichOrElse

Rails le fait via des méthodes de requête attributaires, où, outre false et nil, 0 et "" sont également évaluées sur false 

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

2
Gishu

Pour être aussi idiomatique que possible, je suggérerais ceci.

if val.nil? or val == 0
    # Do something
end

Parce que:

  • Il utilise le néant? méthode.
  • Il utilise l'opérateur "ou", 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.
2
Joshua Swink

Le plus court et le meilleur moyen devrait être 

if val&.>(0)
  # do something
end

Pour val&.>(0)it, la valeur renvoyée est nil lorsque val est nul, car> est également une méthode, nil est égal à false en Ruby. Il retourne false lorsque val == 0.

2
user2097847

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 sauter .nil? et avoir un code légèrement plus court.

[ Mise à jour : Je n'écris plus ce genre de chose. Cela fonctionne mais est trop cryptique. J'ai essayé de réparer mes erreurs en changeant les quelques endroits où je les ai faits.]

En passant, je n’ai pas utilisé .zero? car cela déclenche une exception si val est, par exemple, une chaîne. Mais .zero? conviendrait si vous savez que ce n'est pas le cas.

0
antinome

Au lieu de patcher une classe, vous pouvez utiliser des améliorations à partir de Ruby 2.1. Les raffinements ressemblent au patchage des singes; 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 exagéré 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 améliorations ont été modifiées à la dernière minute pour être intégrées au fichier. Donc, des exemples précédents peuvent avoir montré cela, ce qui ne fonctionnera pas.

class Car
  using NilOrZero
end
0
Mohamad

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 parfois agréable. 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 ifs finissent généralement par cases de toute façon.

Bien sûr, le type 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 itérateurs de Nice.

0
martin

Ceci a la valeur true pour nil et zéro: nil.to_s.to_d == 0

0
Sam
unless (val || 0).zero?

    # do stufff

end
0
Abel

J'aime beaucoup la méthode blank? de Rails 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
0
klew

Je traite cela 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.

0
glenn mcdonald