使用obj.nil?
或obj == nil
是否更好?这两者有什么好处?
答案 0 :(得分:46)
使用obj.nil会更好吗?或obj == nil
它完全一样。它具有与外界完全相同的可观察效果(pfff) *
以及两者的好处是什么。
如果你喜欢微优化全部,对象会将false
返回到.nil?
消息,除了对象nil
本身,而对象使用{ {1}}消息将进行微小的微观比较
与另一个对象一起确定它是否是同一个对象。
* 查看评论。
答案 1 :(得分:11)
就我个人而言,我更喜欢object.nil?
,因为它可能会在较长的行上不那么混乱;但是,如果我在Rails中工作,我通常也会使用object.blank?
,因为它还检查变量是否为空。
答案 2 :(得分:5)
除了语法和风格,我想看看"同样的"测试nil的各种方法是。所以,我写了一些基准来看,并在其上投掷各种形式的零测试。
实际结果显示,在所有情况下使用obj
作为零检查是最快的。 obj
始终比检查obj.nil?
快30%或更多。
令人惊讶的是,obj
的执行速度是obj == nil
的变体的3-4倍,因此似乎会有严重的性能损失。
想要将性能密集型算法加速200%-300%?将所有obj == null
支票转换为obj
。想要打包代码的性能?尽可能在任何地方使用obj == null
。 (开玩笑吧:不要把你的密码包起来!)。
归根结底,请始终使用obj
。这符合Ruby Style Guide规则:Don't do explicit non-nil checks unless you're dealing with boolean values.
好的,所以这些是结果,那么这个基准如何组合,进行了哪些测试,以及结果的细节是什么?
我提出的零检查是:
我选择了各种Ruby类型来测试,以防结果根据类型而改变。这些类型是Fixnum,Float,FalseClass,TrueClass,String和Regex
我在每种类型上使用了这些nil检查条件,以查看它们之间是否存在性能差异。对于每种类型,我测试了nil对象和非nil值对象(例如1_000_000
,100_000.0
,false
,true
,"string"
和{{ 1}})看看在一个nil的对象上检查nil与在一个不是nil的对象上检查nil是否有区别。
完成所有这些后,这里是基准代码:
/\w/
结果很有意思,因为Fixnum,Float和String类型的性能几乎相同,Regex差不多,而FalseClass和TrueClass的执行速度要快得多。在MRI版本1.9.3,2.0.0,2.1.5和2.2.5上进行了测试,各版本的比较结果非常相似。 MRI 2.2.5版本的结果显示在此处(可在the gist中找到:
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
答案 3 :(得分:4)
尽管这两个操作非常不同,但我非常确定它们总能产生相同的结果,至少在某个人的某个边缘决定覆盖Object的#nil?
方法之前。 (一个调用继承自Object的#nil?
方法或在NilClass
中重写,一个与nil
单例进行比较。)
我建议,如果有疑问,你实际上是第三种方式,只是测试一个表达式的真值。
所以,if x
而不是if x == nil
或if x.nil?
,以便在表达式值为 false 时进行此测试DTRT。以这种方式工作也可能有助于避免诱使某人将FalseClass#nil?
定义为 true 。
答案 4 :(得分:3)
您可以在nil?
上使用Symbol#to_proc,而在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
答案 5 :(得分:0)
当你能做到时,我发现自己根本没有使用.nil?
:
unless obj
// do work
end
使用.nil?
实际上速度较慢,但并不明显。 .nil?
只是一种检查该对象是否等于nil的方法,除了视觉吸引力和所需的性能很少之外没有区别。
答案 6 :(得分:-1)
Some可能会建议使用.nil?比简单比较要慢,这在你想到它时才有意义。
但如果你不关注规模和速度,那么.nil?可能更具可读性。