ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

但这似乎很笨拙。

如果 val 等于 false 会发生什么?

u
user513951

对象有一个 nil? method

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

或者,仅针对一条指令:

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

注意“或”和“和”的使用,顺便说一句,与 || 相比,它们具有不同且非常低的优先级和&&。有关一些说明,请参见 blog.jayfields.com/2007/08/…
我同意问题中“气味”的一些海报,但对我来说,这更像是红宝石方式。
or 的优先级在这里不需要任何括号,对于有经验的 Rubyist 来说,它会完全自然地阅读。唯一被 ||or 咬过的人是从未编写过 Perl 的人 :)
唯一需要担心的时候||与 OR 优先级是在分配中,而不是布尔检查。但是,单词的低优先级对于错误检查非常方便。
我认为val && val == 0更好。
n
ndnenkov

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

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

或后缀:

do_something unless val&.nonzero?

这是一个了不起的新的和现代的答案。此外,还有一篇很棒的文章介绍了为什么在此处使用它:The Safe Navigation Operator (&.) in Ruby
非常简洁,但如果没有评论,我需要一点时间才能理解 unless val&.nonzero? 转换为“如果 val 为零或零”
@Stefan,同意。我自己不会在生产代码中使用它。我把它包括在内是为了完成主义。反面是完全可读的 - do_something if val&.nonzero?(也就是如果 val 不是 nil 并且不是零)。
佚名

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


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

您的解决方案很好,其他一些解决方案也很好。

如果你不小心的话,Ruby 可以让你寻找一种漂亮的方式来做任何事情。


M
Mike Deck

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

其次,对我来说,这是一种代码异味,表明您的设计存在潜在缺陷。一般来说,零和零不应该意味着同样的事情。如果可能的话,您应该在点击此代码之前尝试消除 val 为 nil 的可能性,方法是在方法的开头检查它或其他一些机制。

您可能有完全正当的理由这样做,在这种情况下,我认为您的代码很好,但我至少会考虑尽可能摆脱 nil 检查。


非常正确的代码气味! +1 可能会考虑研究 NullObject 模式en.wikipedia.org/wiki/Null_Object_pattern
A
Adrian Dunston

你可以使用 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 的更改,并且可能会使您的代码对其他人无法预测。


我会修改 Numeric 类而不是 Object。
epochwolf,如果你把它放在 Numeric 类上,那么 nil? 将始终返回 false。 nil? 仅在 NilClass 上返回 true。
您可以在 ObjectNilClassNumeric 中实现该方法。 Object 将返回 falseNilClass 将返回 trueNumeric 将返回 zero?
n
ntl

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

val.to_i.zero?

但是,如果 val 曾经是一个不响应 #to_i 的对象,则会出现异常。


供参考:Scott's answer 以及@AndrewGrimm 对此的评价:"5".to_i == 5, but you're more or less right. Clever but doesn't actually work
u
unwind

我相信您的代码不正确;它实际上会测试三个值:nilfalse 和零。这是因为 !val 表达式对于所有为假的值都为真,在 Ruby 中为 nilfalse

我现在能想到的最好的就是

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

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


您可能可以假设有问题的变量是数字。如果您甚至不知道它是布尔值还是数字,代码中就会出现更大的问题。
R
RichOrElse

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

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

G
Gishu

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 很好奇,因为我找不到类似的东西。
这是 Rails/ActiveRecord 即时添加的。如果客户有一个名称字段,名称?自动添加以检查名称是空白还是 nil。请参阅 api.rubyonrails.org/classes/ActiveRecord/Base.html - 搜索“属性查询方法”部分
J
Joshua Swink

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

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

因为:

它使用零?方法。

它使用“或”运算符,比 || 更可取。

它不使用括号,在这种情况下这不是必需的。括号只能在它们用于某些目的时使用,例如覆盖某些运算符的优先级。


虽然我知道这是 7 年前的事,但我因此投了反对票:github.com/bbatsov/ruby-style-guide#no-and-or-or
S
Stanislav Kr.

简短而清晰

[0, nil].include?(val)


也可以反转:val.in? [0,nil]
@mahemoff 这当然是最好的成语!
@mahemoff 更好地使用包括?,因为它比 in 更快?参考:stackoverflow.com/questions/28272550/…
好点子,但我刚才在现代 Ruby 上运行它?单次调用实际上更快,对于 1000 次调用,它们非常相似。无论如何,两者都非常快,以至于很少有应用程序会受到 imo 的影响。 gist.github.com/mahemoff/7232648e1ccb9d23e0f4670913400bd8
d
de-russification

最短和最好的方法应该是

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

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


最短的比什么?,最好的方法是什么?
g
glenn mcdonald

我通过定义一个“是?”来处理这个问题。方法,然后我可以在各种类上以不同的方式实现。所以对于 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

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


k
klew

我真的很喜欢 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

M
Mohamad

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

a
antinome

这非常简洁:

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

只要您不介意将 false 视为与 nil 相同,它就可以工作。在我从事的项目中,这种区别只在一段时间内很重要。其余时间我个人更喜欢跳过 .nil? 并且代码稍微短一些。

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

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


[edited] 我认为如果 val 为 nil,则该表达式的计算结果为 nil == 0(并因此返回 false)。然而,它似乎确实有效,尽管我认为它不是很可读。
我现在认为我这里的方法太神秘了,只是为了保存几个字符,我现在不会这样写。所以我不希望有任何赞成票,但我对一个有效答案的反对票感到有点惊讶(尽管它的味道令人怀疑)......
S
Sam

对于 nil 和零,这评估为 true:nil.to_s.to_d == 0


A
Abel
unless (val || 0).zero?

    # do stufff

end

V
Vasanth Saminathan

在一个单一的伸展,你可以做到这一点:

[do_something] if val.to_i == 0

nil.to_i 将返回 0


S
Scott

另一种解决方案:

if val.to_i == 0
  # do stuff
end

这仅在 val 为整数或 nil 时有效; 0.5.to_i == 0,any_string.to_i == 0,等等。
"5".to_i == 5,但您或多或少是对的。聪明但实际上不起作用。
l
lmumar
val ||= 0
if val == 0
# do something here
end

-1:如果需要保留 val 中的值怎么办?您正在使用这种方法破坏输入数据,并且有更好、破坏性更小的方法来检查零或零。
if (val || 0).zero 怎么样?