最佳红宝石成语为“零或零”


82

我正在寻找一种简洁的方法来检查一个值,看它是否为零或零。目前我正在做类似的事情:

if (!val || val == 0)
  # Is nil or zero
end

但这似乎很笨拙。


1
如果val等于会false怎样?
安德鲁·格林

Answers:


70

对象有零?方法

if val.nil? || val == 0
  [do something]
end

或者,仅需一条指令:

[do something] if val.nil? || val == 0

5
提防使用“或”和“与”,顺便说一句,与||相比,它们具有不同且非常低的优先级。和&&。有关某些说明,请参见blog.jayfields.com/2007/08/…
Mike Woodhouse,

我同意问题中“气味”的某些张贴者,但是对我来说,这更像是红宝石的方式。
琼克

6
or此处的优先级不需要任何原谅,对于有经验的Rubyist来说,它会完全自然地读懂。唯一遭受过||vsor
折磨的

1
您唯一需要担心的|| 与OR优先级在分配中,而不是布尔检查。但是,单词的低优先级对于错误检查可能非常方便。
罗伯特·K

3
我认为val && val == 0更好。
Nakilon

35

如果您真的喜欢方法名称结尾带有问号:


if val.nil? || val.zero?
  # do stuff
end

您的解决方案很好,其他解决方案也不错。

如果您不小心,Ruby可以使您搜索完成所有事情的漂亮方法。


31

从Ruby 2.3.0开始,您可以将安全导航运算符(&.)与结合使用Numeric#nonzero?&.返回nil实例是否为-nilnonzero?-如果数字为0

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

或后缀:

do_something unless val&.nonzero?

这是一个了不起的新现代答案。另外,这里有一篇很棒的文章说明了为什么要使用它:Ruby中的“安全导航运算符(&。)”
Michael Gaskill,2016年

1
非常简洁,但是如果没有评论,我将花一点时间来理解它的unless val&.nonzero?意思是“如果val为零或零”
Stefan

1
@Stefan,同意。我自己不会在生产代码中使用它。我把它包括进来是为了完成主义。相反,它是完全可读的- do_something if val&.nonzero?(又名if valis not niland not zero)。
ndnenkov

29

首先,我认为这是您可以检查特定条件的最简洁方法。

其次,对我来说,这是一种代码气味,表明您的设计中存在潜在的缺陷。通常,nil和0不应表示同一件事。如果可能的话,您应该尝试在方法开始之前或其他某种机制进行检查,以消除val变为nil的可能性。

在这种情况下,您可能有一个完全合理的理由,在这种情况下,我认为您的代码是好的,但我至少会考虑尝试摆脱nil检查(如果可能)。


4
关于代码气味非常正确!+1可能考虑研究NullObject模式en.wikipedia.org/wiki/Null_Object_pattern
abyx

9

您可以使用Object.nil吗?具体测试是否为零(并且不会陷入false和nil之间)。您也可以将方法猴子插入对象。

class Object
   def nil_or_zero?
     return (self.nil? or self == 0)
   end
end

my_object = MyClass.new
my_object.nil_or_zero?
==> false

不建议这样做,因为对同事的更改很难跟踪到对象,并且可能会使您的代码对其他人不可预测。


我将修改数值类而不是对象。
epochwolf,

6
epochwolf,如果将其放在Numeric类上,nil?则将始终返回false。nil?仅在NilClass上返回true。
Ryan McGeary 09年

你可以实现的方法ObjectNilClassNumericObject将返回falseNilClass将返回true并且Numeric将返回zero?
Stefan

6

nil.to_i返回零,所以我经常这样做:

val.to_i.zero?

但是,如果val是不响应#to_i的对象,则将获得异常。


供参考:斯科特的答案和@AndrewGrimm说的话:"5".to_i == 5, but you're more or less right. Clever but doesn't actually work
Paul van Leeuwen

4

我认为您的代码不正确;它实际上将测试三个值:nilfalse,和为零。这是因为!val对于所有false值(在Ruby中为niland),该表达式均为true false

我现在能想到的最好的方法是

if val == nil || val == 0
  # do stuff
end

当然哪一个不是很聪明,但是(非常)清楚。


您可能会假设所讨论的变量是数字。如果您甚至不知道它是布尔值还是数字值,那么代码中就会遇到更大的问题。
Mike Deck

我会用.nil吗?不是==无
RichH

4

我的解决方案还使用优化,减去条件。

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

2

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,因为我找不到这样的东西。
mrzasa 2012年

这是Rails / ActiveRecord即时添加的。如果客户有一个名称字段,名称?会自动添加以检查名称是否为空白或无。请参阅api.rubyonrails.org/classes/ActiveRecord/Base.html-搜索“属性查询方法”部分
Gishu,2012年

2

为了尽可能地习惯,我建议这样做。

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

因为:

  • 它使用nil吗?方法。
  • 它使用“或”运算符,它优于||。
  • 它不使用括号,在这种情况下不需要。仅当括号用于某些目的(例如,覆盖某些运算符的优先级)时才应使用括号。

1
尽管我知道这实际上是7年前的事情,但由于这个原因,我投了反对票
Devon Parsons,

2

简短明了

[0, nil].include?(val)


2
也可以扭转这种情况:val.in? [0,nil]
mahemoff '16

1
@mahemoff无疑是最好的成语!
intmarinoreturn0

@mahemoff更好地使用include ?,因为它比in更快?参考:stackoverflow.com/questions/28272550/...
拉克哈尼Aliraza

好点,但是我现在在现代Ruby上以及在其中运行它?实际上,单个调用的速度更快,而1000个调用的速度却非常相似。无论如何,两者都非常快速,足以使imo很少有应用程序受到影响。gist.github.com/mahemoff/7232648e1ccb9d23e0f4670913400bd8
mahemoff

2

最短最好的方法应该是

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

因为val&.>(0) 当val为nil时它返回nil,因为>基本上也是一种方法,nil在ruby中等于false。当时返回false val == 0


3
最短的方法是什么?
塞巴斯蒂安·帕尔玛

0

我通过定义“是”来解决这个问题。方法,然后可以在各种类上以不同的方式实现。那么对于Array,“是”吗?表示“大小> 0”;对于Fixnum,它的意思是“ self!= 0”;对于String,它的意思是“ self!=”。NilClass当然定义了“是”?只是返回零。


0

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通常都会以cases结尾。

当然Enum.any?/Enum.include?某种类型的作品也...如果您想真正地获得神秘的话:

if [0, nil].include? val
    #do stuff
end

正确的做法当然是定义方法或函数。或者,如果必须对多个值执行相同的操作,请结合使用这些不错的迭代器。


0

我真的很喜欢的Railsblank?的那种事情的方法,但它不会返回true0。因此,您可以添加方法:

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

0

代替猴子修补类,您可以使用从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

在最后一分钟更改优化,以限制到文件范围。因此,较早的示例可能已经表明了这一点,但这将不起作用。

class Car
  using NilOrZero
end

0

这很简洁:

if (val || 0) == 0
  # Is nil, false, or zero.
end

只要您不介意false与一样,它就会起作用nil。在我从事的项目中,这种区别有时只是很重要。剩下的时间我个人更喜欢跳过,.nil?并且代码略短。

[更新:我不再写这种东西了。它可以工作,但是太神秘了。我试图通过改变我做的几个地方来纠正我的错误行为。]

顺便说一句,我没有使用过,.zero?因为这会引发异常val,例如字符串。但是.zero?,如果您知道不是这种情况,那会很好。


[edited]我以为如果val为零,那么此表达式的计算结果为nil == 0(因此返回false)。但是,它似乎确实起作用,尽管我认为它不是很可读。
omn​​ikron '16

我现在相信我在这里的方法太神秘了,只是为了节省一些字符,而且现在我不会这样写了。所以我不希望有任何投票,但是我对投票的有效答案感到有些惊讶(尽管它的味道令人怀疑)...
antinome

0

对于nil和零,此值为true: nil.to_s.to_d == 0



-1

另一个解决方案:

if val.to_i == 0
  # do stuff
end

1
仅在val为整数或nil时有效;0.5.to_i == 0,any_string.to_i == 0,依此类推
Zach Langley,

"5".to_i == 5,但您或多或少是对的。聪明,但实际上不起作用。
安德鲁·格林

-3
val ||= 0
if val == 0
# do something here
end

3
-1:如果val需要保留in的值怎么办?您正在使用这种方法破坏输入数据,并且有更好的,破坏性较小的方法来检查nil或0。
白金Azure

3
if(val || 0).zero怎么样?
timkay 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.