「ゼロまたはゼロ」に最適なルビのイディオム
-
03-07-2019 - |
質問
値が nil か 0 かを確認する簡潔な方法を探しています。現在、私は次のようなことをしています:
if (!val || val == 0)
# Is nil or zero
end
しかし、これは非常に不格好に思えます。
解決
オブジェクトには nil?がありますメソッド。
if val.nil? || val == 0
[do something]
end
または、たった1つの指示で:
[do something] if val.nil? || val == 0
他のヒント
最後に疑問符が付いたメソッド名が本当に好きな場合:
if val.nil? || val.zero?
# do stuff
end
他のいくつかのソリューションと同様に、あなたのソリューションは問題ありません。
Rubyを使用すると、気をつけなければ、すべてを実行するためのきれいな方法を検索できます。
まず最初に、それがその特定の状態をチェックできる最も簡潔な方法だと思います。
第二に、これはデザインの潜在的な欠陥を示すコードの匂いです。一般に、nilとzeroは同じことを意味するべきではありません。可能であれば、このコードをヒットする前に、メソッドの先頭またはその他のメカニズムでチェックすることにより、valがnilになる可能性を排除するようにしてください。
これを行う完全に正当な理由があるかもしれません。その場合、コードは良いと思いますが、可能であれば、nilチェックを取り除くことを検討することを少なくとも検討します。
Ruby 2.3.0以降では、安全なナビゲーション演算子(&。
)と Numeric#nonzero?
。 &。
は、インスタンスが nil
で nonzero?
の場合 nil
を返します-数字が 0の場合
:
unless val&.nonzero?
# Is nil or zero
end
または後置:
do_something unless val&.nonzero?
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
、およびゼロの3つの値をテストします。これは、!val
式がfalseのすべての値に対してtrueであるためです。Rubyでは、これは nil
および false
です。
私が今思いつくことができる最高のものは
if val == nil || val == 0
# do stuff
end
もちろん、それほど賢いわけではありませんが、(非常に)明確です。
nil.to_iはゼロを返すので、私はこれをよくします:
val.to_i.zero?
ただし、valが#to_iに応答しないオブジェクトである場合、例外が発生します。
私のソリューションでは、条件を除いた絞り込みも使用しています。
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と""また、偽と評価されます。
if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation
ただし、中傷者の割合があります。 http://www.joegrossberg.com/archives/002995.html
可能な限りイディオムにするには、これをお勧めします。
if val.nil? or val == 0
# Do something
end
理由:
- nilを使用しますか?メソッド。
- 「または」を使用します; ||。 よりも望ましい演算子
- この場合は必要ない括弧を使用しません。括弧は、特定の演算子の優先順位をオーバーライドするなど、何らかの目的に役立つ場合にのみ使用してください。
最短かつ最良の方法
if val&.>(0)
# do something
end
val&。>(0)
の場合
valがnilの場合は>からnilを返します。基本的にメソッドでもあり、ルビーではnilはfalseに等しい。 val == 0
の場合はfalseを返します。
短縮してクリア
[0、nil] .include?(val)
「is?」を定義してこれに対処します;このメソッドは、さまざまなクラスで異なる方法で実装できます。配列の場合、「is?」は「サイズ> 0」を意味します。 Fixnumでは、「自己!= 0」を意味します。 Stringの場合は、" self!= ''"を意味します。もちろん、NilClassは「is?」を定義します;単にnilを返すように。
使用できます 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
クラスにモンキーパッチを適用する代わりに、使用できますRuby 2.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
これは非常に簡潔です:
if (val || 0) == 0
# Is nil, false, or zero.
end
false
を nil
と同じように扱うことを気にしない限り機能します。私が取り組んだプロジェクトでは、その区別はたまにしか重要ではありません。残りの時間は個人的に .nil?
をスキップし、コードを少し短くすることを好みます。
[更新:この種のことはもう書かない。それは動作しますが、あまりにも不可解です。私はそれをしたいくつかの場所を変えることによって、私の悪行を正そうとしました。]
ところで、 .zero?
は使用しませんでした。これは、たとえば val
が文字列の場合に例外が発生するためです。ただし、そうでないことがわかっている場合は、 .zero?
で問題ありません。
これは、nilおよびゼロに対してtrueと評価されます。 nil.to_s.to_d == 0
unless (val || 0).zero?
# do stufff
end
別の解決策:
if val.to_i == 0
# do stuff
end
val ||= 0
if val == 0
# do something here
end