Est-il préférable d'utiliser obj.nil?
ou obj == nil
Et quels sont les avantages des deux?
Est-il préférable d'utiliser obj.nil? ou obj == nil
C'est exactement le meme. Il a exactement les mêmes effets observables de l'extérieur (pfff) *
et quels sont les avantages des deux.
Si vous aimez les micro-optimisations tous Les objets retourneront false
au .nil?
Message sauf pour l'objet nil
lui-même, tandis que l'objet utilisant le ==
Le message effectuera une minuscule comparaison micro avec l'autre objet pour déterminer s'il s'agit du même objet.
* Voir les commentaires.
Personnellement, je préfère object.nil?
Comme cela peut être moins déroutant sur des lignes plus longues; Cependant, j'utilise aussi généralement object.blank?
Si je travaille dans Rails Comme cela vérifie également la vue si la variable est vide.
Syntaxe et style de côté, je voulais voir comment "les mêmes" diverses approches des tests pour NIL étaient. Donc, j'ai écrit quelques points de repère à voir et j'ai jeté diverses formes de tests nul.
Les résultats réels ont montré que l'utilisation de obj
comme une vérification nulle est la plus rapide dans tous les cas. obj
_ est toujours plus rapide de 30% ou plus que la vérification obj.nil?
.
Étonnamment, obj
_ Effectue environ 3 à 4 fois plus vite que les variations de obj == nil
, Pour laquelle il semble y avoir une pénalité de performance punaise.
Voulez-vous accélérer votre algorithme à forte intensité de performance de 200% à 300%? Convertissez tout obj == null
Vérifie à obj
. Vous voulez sander la performance de votre code? Utilisez obj == null
Partout que vous pouvez. (Je plaisante: ne sandez pas votre code!).
Dans l'analyse finale, utilisez toujours obj
. Que les Jives avec le Guide de style rubis règle: Ne faites pas de vérification explicite non-NIL, sauf si vous avez affaire à des valeurs booléennes.
OK, donc ce sont les résultats. Comment se passe-t-il ce point de référence, quels tests ont été effectués et quels sont les détails des résultats?
La NIL vérifie que je suis venu avec:
J'ai choisi diverses Ruby types à tester au cas où les résultats changés en fonction du type. Ces types étaient fixnum, flotteur, falsiflass, trueclass, chaîne et regex
J'ai utilisé ces conditions de vérification nulle sur chacun des types pour voir s'il y avait une différence entre eux, la performance sage. Pour chaque type, j'ai testé les objets NIV et les objets de valeur non nul (par exemple, 1_000_000
, 100_000.0
, false
, true
, "string"
, et /\w/
) Pour voir s'il y a une différence de vérification de NIL sur un objet nul contre un objet qui n'est pas nulle.
Avec tout cela hors de la route, voici le code de référence:
require 'benchmark'
nil_obj = nil
N = 10_000_000
puts Ruby_DESCRIPTION
[1_000_000, 100_000.0, false, true, "string", /\w/].each do |obj|
title = "#{obj} (#{obj.class.name})"
puts "============================================================"
puts "Running tests for obj = #{title}"
Benchmark.bm(15, title) do |x|
implicit_obj_report = x.report("obj:") { N.times { obj } }
implicit_nil_report = x.report("nil_obj:") { N.times { nil_obj } }
explicit_obj_report = x.report("obj.nil?:") { N.times { obj.nil? } }
explicit_nil_report = x.report("nil_obj.nil?:") { N.times { nil_obj.nil? } }
not_obj_report = x.report("!obj:") { N.times { !obj } }
not_nil_report = x.report("!nil_obj:") { N.times { !nil_obj } }
not_not_obj_report = x.report("!!obj:") { N.times { !!obj } }
not_not_nil_report = x.report("!!nil_obj:") { N.times { !!nil_obj } }
equals_obj_report = x.report("obj == nil:") { N.times { obj == nil } }
equals_nil_report = x.report("nil_obj == nil:") { N.times { nil_obj == nil } }
not_equals_obj_report = x.report("obj != nil:") { N.times { obj != nil } }
not_equals_nil_report = x.report("nil_obj != nil:") { N.times { nil_obj != nil } }
end
end
Les résultats étaient intéressants, car les performances de fixnum, de flotteur et de chaîne ont été pratiquement identiques, la falsification et la fausseclass et la trueclass ont été beaucoup plus rapidement rapidement. Des tests ont été effectués sur des versions IRM 1.9.3, 2.0.0, 2.1.5 et 2.2.5 avec des résultats comparatifs très similaires sur les versions. Les résultats de la version IRM 2.2.5 sont présentés ici (et disponibles dans The Gist :
Ruby 2.2.5p319 (2016-04-26 revision 54774) [x86_64-darwin14]
============================================================
Running tests for obj = 1000000 (Fixnum)
user system total real
obj: 0.970000 0.000000 0.970000 ( 0.987204)
nil_obj: 0.980000 0.010000 0.990000 ( 0.980796)
obj.nil?: 1.250000 0.000000 1.250000 ( 1.268564)
nil_obj.nil?: 1.280000 0.000000 1.280000 ( 1.287800)
!obj: 1.050000 0.000000 1.050000 ( 1.064061)
!nil_obj: 1.070000 0.000000 1.070000 ( 1.170393)
!!obj: 1.110000 0.000000 1.110000 ( 1.122204)
!!nil_obj: 1.120000 0.000000 1.120000 ( 1.147679)
obj == nil: 2.110000 0.000000 2.110000 ( 2.137807)
nil_obj == nil: 1.150000 0.000000 1.150000 ( 1.158301)
obj != nil: 2.980000 0.010000 2.990000 ( 3.041131)
nil_obj != nil: 1.170000 0.000000 1.170000 ( 1.203015)
============================================================
Running tests for obj = 100000.0 (Float)
user system total real
obj: 0.940000 0.000000 0.940000 ( 0.947136)
nil_obj: 0.950000 0.000000 0.950000 ( 0.986488)
obj.nil?: 1.260000 0.000000 1.260000 ( 1.264953)
nil_obj.nil?: 1.280000 0.000000 1.280000 ( 1.306817)
!obj: 1.050000 0.000000 1.050000 ( 1.058924)
!nil_obj: 1.070000 0.000000 1.070000 ( 1.096747)
!!obj: 1.100000 0.000000 1.100000 ( 1.105708)
!!nil_obj: 1.120000 0.010000 1.130000 ( 1.132248)
obj == nil: 2.140000 0.000000 2.140000 ( 2.159595)
nil_obj == nil: 1.130000 0.000000 1.130000 ( 1.151257)
obj != nil: 3.010000 0.000000 3.010000 ( 3.042263)
nil_obj != nil: 1.170000 0.000000 1.170000 ( 1.189145)
============================================================
Running tests for obj = false (FalseClass)
user system total real
obj: 0.930000 0.000000 0.930000 ( 0.933712)
nil_obj: 0.950000 0.000000 0.950000 ( 0.973776)
obj.nil?: 1.250000 0.000000 1.250000 ( 1.340943)
nil_obj.nil?: 1.270000 0.010000 1.280000 ( 1.282267)
!obj: 1.030000 0.000000 1.030000 ( 1.039532)
!nil_obj: 1.060000 0.000000 1.060000 ( 1.068765)
!!obj: 1.100000 0.000000 1.100000 ( 1.111930)
!!nil_obj: 1.110000 0.000000 1.110000 ( 1.115355)
obj == nil: 1.110000 0.000000 1.110000 ( 1.121403)
nil_obj == nil: 1.100000 0.000000 1.100000 ( 1.114550)
obj != nil: 1.190000 0.000000 1.190000 ( 1.207389)
nil_obj != nil: 1.140000 0.000000 1.140000 ( 1.181232)
============================================================
Running tests for obj = true (TrueClass)
user system total real
obj: 0.960000 0.000000 0.960000 ( 0.964583)
nil_obj: 0.970000 0.000000 0.970000 ( 0.977366)
obj.nil?: 1.260000 0.000000 1.260000 ( 1.265229)
nil_obj.nil?: 1.270000 0.010000 1.280000 ( 1.283342)
!obj: 1.040000 0.000000 1.040000 ( 1.059689)
!nil_obj: 1.070000 0.000000 1.070000 ( 1.068290)
!!obj: 1.120000 0.000000 1.120000 ( 1.154803)
!!nil_obj: 1.130000 0.000000 1.130000 ( 1.155932)
obj == nil: 1.100000 0.000000 1.100000 ( 1.102394)
nil_obj == nil: 1.130000 0.000000 1.130000 ( 1.160324)
obj != nil: 1.190000 0.000000 1.190000 ( 1.202544)
nil_obj != nil: 1.200000 0.000000 1.200000 ( 1.200812)
============================================================
Running tests for obj = string (String)
user system total real
obj: 0.940000 0.000000 0.940000 ( 0.953357)
nil_obj: 0.960000 0.000000 0.960000 ( 0.962029)
obj.nil?: 1.290000 0.010000 1.300000 ( 1.306233)
nil_obj.nil?: 1.240000 0.000000 1.240000 ( 1.243312)
!obj: 1.030000 0.000000 1.030000 ( 1.046630)
!nil_obj: 1.060000 0.000000 1.060000 ( 1.123925)
!!obj: 1.130000 0.000000 1.130000 ( 1.144168)
!!nil_obj: 1.130000 0.000000 1.130000 ( 1.147330)
obj == nil: 2.320000 0.000000 2.320000 ( 2.341705)
nil_obj == nil: 1.100000 0.000000 1.100000 ( 1.118905)
obj != nil: 3.040000 0.010000 3.050000 ( 3.057040)
nil_obj != nil: 1.150000 0.000000 1.150000 ( 1.162085)
============================================================
Running tests for obj = (?-mix:\w) (Regexp)
user system total real
obj: 0.930000 0.000000 0.930000 ( 0.939815)
nil_obj: 0.960000 0.000000 0.960000 ( 0.961852)
obj.nil?: 1.270000 0.000000 1.270000 ( 1.284321)
nil_obj.nil?: 1.260000 0.000000 1.260000 ( 1.275042)
!obj: 1.040000 0.000000 1.040000 ( 1.042543)
!nil_obj: 1.040000 0.000000 1.040000 ( 1.047280)
!!obj: 1.120000 0.000000 1.120000 ( 1.128137)
!!nil_obj: 1.130000 0.000000 1.130000 ( 1.138988)
obj == nil: 1.520000 0.010000 1.530000 ( 1.529547)
nil_obj == nil: 1.110000 0.000000 1.110000 ( 1.125693)
obj != nil: 2.210000 0.000000 2.210000 ( 2.226783)
nil_obj != nil: 1.170000 0.000000 1.170000 ( 1.169347)
Bien que les deux opérations soient très différentes, je suis sûr qu'ils produiront toujours le même résultat, du moins jusqu'à ce que quelqu'un sur le bord de quelque chose décide de remplacer l'objet #nil?
méthode. (On appelle le #nil?
méthode héritée d'objet ou de remplacement dans NilClass
et une compare contre le nil
singleton.)
Je suggérerais que, en cas de doute, vous passez une troisième voie, réellement, et testez simplement la valeur de vérité d'une expression.
Donc, if x
et pas if x == nil
ou if x.nil?
, afin d'avoir ce test DTRT lorsque la valeur d'expression est FALSE. Travailler de cette manière peut également aider à éviter de tenter quelqu'un de définir FalseClass#nil?
comme vrai.
Vous pouvez utiliser le symbole # to_proc sur nil?
, tandis que cela ne serait pas pratique sur x == nil
.
arr = [1, 2, 3]
arr.any?(&:nil?) # Can be done
arr.any?{|x| x == nil} # More verbose, and I suspect is slower on Ruby 1.9.2
! arr.all? # Check if any values are nil or false
Je me trouve pas en utilisant .nil?
du tout quand vous pouvez faire:
unless obj
// do work
end
Il est effectivement plus lent en utilisant .nil?
mais pas sensiblement. .nil?
est juste une méthode pour vérifier si cet objet est égal à nil, autre que l'attrait visuel et très peu de performances qu'il faut qu'il n'y a pas de différence.