我正在寻找一种简洁的方法来检查一个值,看看它是零还是零。目前我正在做类似的事情:
if (!val || val == 0)
# Is nil or zero
end
但这似乎很笨拙。
false
会发生什么?
对象有一个 nil? method。
if val.nil? || val == 0
[do something]
end
或者,仅针对一条指令:
[do something] if val.nil? || val == 0
从 Ruby 2.3.0 开始,您可以将安全导航运算符 (&.
) 与 Numeric#nonzero?
结合使用。如果实例为 nil
,则 &.
返回 nil
,如果实例为 nonzero?
,则返回 0
:
unless val&.nonzero?
# Is nil or zero
end
或后缀:
do_something unless val&.nonzero?
unless val&.nonzero?
转换为“如果 val 为零或零”
do_something if val&.nonzero?
(也就是如果 val
不是 nil
并且不是零)。
如果您真的喜欢末尾带有问号的方法名称:
if val.nil? || val.zero?
# do stuff
end
您的解决方案很好,其他一些解决方案也很好。
如果你不小心的话,Ruby 可以让你寻找一种漂亮的方式来做任何事情。
首先,我认为这是检查特定条件的最简洁方法。
其次,对我来说,这是一种代码异味,表明您的设计存在潜在缺陷。一般来说,零和零不应该意味着同样的事情。如果可能的话,您应该在点击此代码之前尝试消除 val 为 nil 的可能性,方法是在方法的开头检查它或其他一些机制。
您可能有完全正当的理由这样做,在这种情况下,我认为您的代码很好,但我至少会考虑尽可能摆脱 nil 检查。
你可以使用 Object.nil 吗?专门测试 nil (而不是陷入 false 和 nil 之间)。您也可以将方法修补到 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
不建议这样做,因为同事很难跟踪对 Object 的更改,并且可能会使您的代码对其他人无法预测。
nil?
将始终返回 false。 nil?
仅在 NilClass 上返回 true。
Object
、NilClass
和 Numeric
中实现该方法。 Object
将返回 false
,NilClass
将返回 true
,Numeric
将返回 zero?
。
nil.to_i 返回零,所以我经常这样做:
val.to_i.zero?
但是,如果 val 曾经是一个不响应 #to_i 的对象,则会出现异常。
"5".to_i == 5, but you're more or less right. Clever but doesn't actually work
我相信您的代码不正确;它实际上会测试三个值:nil
、false
和零。这是因为 !val
表达式对于所有为假的值都为真,在 Ruby 中为 nil
和 false
。
我现在能想到的最好的就是
if val == nil || val == 0
# do stuff
end
这当然不是很聪明,但(非常)清楚。
我的解决方案还使用细化,减去条件。
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 通过属性查询方法做到这一点,除了 false 和 nil 之外,0 和 "" 也计算为 false。
if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation
然而,它也有批评者的份额。 http://www.joegrossberg.com/archives/002995.html
#attribute
很好奇,因为我找不到类似的东西。
为了尽可能地道,我建议这样做。
if val.nil? or val == 0
# Do something
end
因为:
它使用零?方法。
它使用“或”运算符,比 || 更可取。
它不使用括号,在这种情况下这不是必需的。括号只能在它们用于某些目的时使用,例如覆盖某些运算符的优先级。
简短而清晰
[0, nil].include?(val)
val.in? [0,nil]
最短和最好的方法应该是
if val&.>(0)
# do something
end
对于 val&.>(0)
,它在 val 为 nil 时返回 nil,因为 >基本上也是一种方法,在ruby中nil等于false。 val == 0
时返回 false。
我通过定义一个“是?”来处理这个问题。方法,然后我可以在各种类上以不同的方式实现。所以对于 Array,“是?”表示“大小>0”;对于 Fixnum,它的意思是“自我!= 0”;对于字符串,它的意思是“自我!=''”。 NilClass 当然定义了“是?”就像返回零一样。
如果您愿意,可以使用 case
:
case val with nil, 0
# do stuff
end
然后您可以使用任何与 ===
一起使用的东西,这有时很好。或者做这样的事情:
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
它不是完全好的 OOP,但它非常灵活并且有效。无论如何,我的 if
通常最终会变成 case
。
当然 Enum.any?
/Enum.include?
也可以使用……如果您想变得非常神秘:
if [0, nil].include? val
#do stuff
end
正确的做法当然是定义一个方法或函数。或者,如果您必须对许多值执行相同的操作,请结合使用这些不错的迭代器。
我真的很喜欢 Rails blank?
方法来处理这类事情,但它不会为 0
返回 true
。所以你可以添加你的方法:
def nil_zero?
if respond_to?(:zero?)
zero?
else
!self
end
end
它会检查某个值是 nil 还是 0:
nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false
if val.nil_zero?
#...
end
you could use refinements 从 Ruby 2.1 开始,而不是猴子修补类。细化类似于猴子补丁;在那里,它们允许您修改类,但修改仅限于您希望使用它的范围。
如果您想进行一次此检查,这有点过头了,但如果您重复自己,这是猴子修补的一个很好的替代方案。
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
Refinements were changed 在最后一分钟被限定为文件。所以早期的例子可能已经表明了这一点,这是行不通的。
class Car
using NilOrZero
end
这非常简洁:
if (val || 0) == 0
# Is nil, false, or zero.
end
只要您不介意将 false
视为与 nil
相同,它就可以工作。在我从事的项目中,这种区别只在一段时间内很重要。其余时间我个人更喜欢跳过 .nil?
并且代码稍微短一些。
[更新:我不再写这种东西了。它有效,但太神秘了。我试图通过改变我做过的几个地方来纠正我的错误行为。]
顺便说一句,我没有使用 .zero?
,因为如果 val
是一个字符串,这会引发异常。但如果您知道情况并非如此,.zero?
会很好。
[edited]
我认为如果 val
为 nil,则该表达式的计算结果为 nil == 0
(并因此返回 false
)。然而,它似乎确实有效,尽管我认为它不是很可读。
对于 nil 和零,这评估为 true:nil.to_s.to_d == 0
unless (val || 0).zero?
# do stufff
end
在一个单一的伸展,你可以做到这一点:
[do_something] if val.to_i == 0
nil.to_i
将返回 0
另一种解决方案:
if val.to_i == 0
# do stuff
end
"5".to_i == 5
,但您或多或少是对的。聪明但实际上不起作用。
val ||= 0
if val == 0
# do something here
end
val
中的值怎么办?您正在使用这种方法破坏输入数据,并且有更好、破坏性更小的方法来检查零或零。
or
的优先级在这里不需要任何括号,对于有经验的 Rubyist 来说,它会完全自然地阅读。唯一被||
与or
咬过的人是从未编写过 Perl 的人 :)val && val == 0
更好。