「ゼロまたはゼロ」に最適なルビーのイディオム


83

値がゼロかゼロかを確認するための簡潔な方法を探しています。現在、私は次のようなことをしています。

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

しかし、これは非常に不器用なようです。


1
valが等しい場合はどうなりfalseますか?
Andrew Grimm

回答:


70

オブジェクトにはnilがありますか?メソッド

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

または、たった1つの命令の場合:

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

5
「or」と「and」の使用に注意してください。ところで、これらは||と比較して優先順位が異なり、非常に低くなっています。および&&。いくつかのコメントについては、blog.jayfields.com / 2007/08 /…を参照してください。
マイクウッドハウス

私は質問の「におい」のポスターに同意しますが、私にとってこれはもっとルビーな方法です。
ジョンケ

6
の優先順位はorここでは親子関係を必要とせず、経験豊富なRubyistに完全に自然に読まれます。||対に噛まれorたことがあるのは、Perlをプログラムしたことがない人だけです:)
ephemient 2008年

1
あなたが心配する必要がある唯一の時|| 対OR優先順位は、ブールチェックではなく割り当てにあります。ただし、単語の優先順位が低いと、エラーチェックに非常に便利です。
ロバートK

3
val && val == 0はより良いと思います。
ナキロン2010

35

末尾に疑問符が付いたメソッド名が本当に好きな場合:


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

他のいくつかのソリューションと同様に、あなたのソリューションは問題ありません。

あなたが注意しなければ、Rubyはあなたにすべてをするためのきれいな方法を探させることができます。


32

Ruby 2.3.0以降では、安全なナビゲーション演算子(&.)をNumeric#nonzero?。と組み合わせることができます。&.返すnilインスタンスであった場合nilnonzero?-数であった場合0

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

または接尾辞:

do_something unless val&.nonzero?

これは素晴らしい新しい現代的な答えでした。また、なぜそれを使用するのかについての素晴らしい記事がここにあります:RubyのSafe Navigation Operator(&。)
Michael Gaskill 2016年

1
非常に簡潔ですが、コメントがなけれunless val&.nonzero?ば、「valがゼロまたはゼロの場合」に変換されることを理解するのに少し時間がかかります
Stefan

1
@Stefan、同意しました。私自身はこれを本番コードでは使用しません。完成主義のためにそれを含めました。ただし、その逆は完全に読み取り可能です- do_something if val&.nonzero?(そうvalでない場合nilやゼロでない場合)。
ndnenkov 2017年

29

まず、それがその特定の状態をチェックできる最も簡潔な方法だと思います。

第二に、私にとってこれはあなたのデザインの潜在的な欠陥を示すコードの臭いです。一般に、nilとzeroは同じことを意味するべきではありません。可能であれば、メソッドの最初または他のメカニズムでチェックすることにより、このコードをヒットする前にvalがnilになる可能性を排除するようにしてください。

これを行う完全に正当な理由があるかもしれません。その場合、コードは適切だと思いますが、可能であれば、少なくともnilチェックを削除することを検討したいと思います。


4
コードの臭いについては非常に正しいです!+1はNullObjectパターンに探して検討するかもしれないen.wikipedia.org/wiki/Null_Object_pattern
abyx

9

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への変更は同僚が追跡するのが難しく、コードが他の人に予測できない可能性があるため、これはお勧めしません。


ObjectではなくNumericクラスを変更します。
epochwolf 2008年

6
epochwolf、これをNumericクラスに置くnil?と、常にfalseが返されます。nil?NilClassでのみtrueを返します。
Ryan McGeary

あなたは内のメソッドを実装することができObjectNilClassそしてNumericObject返すfalseNilClass返されるtrueNumeric返すでしょうzero?
ステファン

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

4

あなたのコードは間違っていると思います。:それは、実際のテストでは三つの値のための意志nilfalseとゼロ。これは、ある!val式はRubyである偽のあるすべての値について真であるnilfalse

私が今思いつくことができる最高のものは

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

もちろん、これはあまり賢くはありませんが、(非常に)明確です。


問題の変数は数値であると想定できます。それがブール値であるか数値であるかさえわからない場合は、コードに大きな問題があります。
マイクデッキ

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がその場で追加するものです。顧客に名前フィールドがある場合、名前は?名前が空白かnilかを確認するために自動追加されます。参照api.rubyonrails.org/classes/ActiveRecord/Base.html - 「属性検索方法」のセクションを検索
Gishu

2

できるだけ慣用的にするために、これをお勧めします。

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

理由:

  • それはnilを使用しますか?方法。
  • ||よりも望ましい「or」演算子を使用します。
  • この場合は必要ない括弧は使用しません。括弧は、特定の演算子の優先順位を上書きするなど、何らかの目的に役立つ場合にのみ使用する必要があります。

1
これは文字通り7年前のものであることはわかっていますが、このために反対票を投じました:github.com/bbatsov/ruby-style-guide#no-and-or-or
Devon Parsons

2

短くて明確

[0, nil].include?(val)


2
それを元に戻すこともできます:val.in? [0,nil]
mahemoff 2016年

1
@mahemoffは確かにそれにとって最良のイディオムです!
intmarinoreturn0

@mahemoffの方が良い使用法は含まれていますか?REF:stackoverflow.com/questions/28272550/...
Lakhani Aliraza

良い点ですが、私は今それを現代のRubyで実行しましたか?実際には、1回の呼び出しの方が高速で、1000回の呼び出しの場合は非常に似ています。いずれにせよ、どちらも非常に高速であり、imoに影響を与えるアプリケーションはほとんどありません。gist.github.com/mahemoff/7232648e1ccb9d23e0f4670913400bd8
mahemoff

2

最短かつ最良の方法は

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

ためval&.>(0) valがゼロである場合にも基本的な方法である>ので、それはnilを返し、Rubyで偽に等しいNIL。の場合はfalseを返しますval == 0


3
何よりも最短?、何よりも最善の方法?
セバスチャンパルマ

0

私は「is?」を定義することによってこれに対処します。メソッド。これをさまざまなクラスに異なる方法で実装できます。つまり、Arrayの場合、「is?」「サイズ> 0」を意味します。Fixnumの場合、「self!= 0」を意味します。文字列の場合、「self!= ''」を意味します。もちろん、NilClassは「is?」を定義します。ちょうどnilを返すように。


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のは通常、caseとにかくsとして終わります。

もちろんEnum.any?/Enum.include?一種の作品も...あなたが本当に謎めいたものになりたいのなら:

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

もちろん、正しいことはメソッドまたは関数を定義することです。または、多くの値で同じことを行う必要がある場合は、それらの優れたイテレータを組み合わせて使用​​します。


0

私は実際にRailsのようなblank?もののようなもののための方法、それは戻りませんtrueため0。したがって、メソッドを追加できます。

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

クラスにモンキーパッチを適用する代わりに、Ruby2.1以降の改良版を使用できます。改良はモンキーパッチに似ています。その点で、クラスを変更できますが、変更は、使用するスコープに限定されます。

このチェックを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]valnilの場合、この式は次のように評価されるnil == 0(したがって、戻るfalse)と思いました。しかし、私はそれがあまり読みやすいとは思わないが、それは実際に機能しているように見える。
omn​​ikron 2016年

私は今、ここでの私のアプローチは、ほんの数文字を節約するにはあまりにも不可解であると信じており、今日ではこのように書くことはしません。だから私は賛成票を期待していませんが、(それは疑わしい味でしたが)
実用的

0

これは、nilとzeroの場合に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、しかしあなたは多かれ少なかれ正しいです。賢いですが、実際には機能しません。
Andrew Grimm

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

3
-1:の値をval維持する必要がある場合はどうなりますか?このメソッドを使用して入力データを破壊しているので、nilまたは0をチェックするためのより優れた破壊的でない方法があります。
プラチナアズール

3
if(val || 0).zeroはどうですか?
timkay 2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.