"Nil or zero" için en iyi ruby ​​deyimi


83

Sıfır mı yoksa sıfır mı olduğunu görmek için bir değeri kontrol etmenin kısa bir yolunu arıyorum. Şu anda şöyle bir şey yapıyorum:

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

Ama bu çok sakar görünüyor.


1
Val eşitse ne olmalı false?
Andrew Grimm

Yanıtlar:


70

Nesnelerin sıfır mı var ? yöntem .

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

Veya sadece bir talimat için:

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

5
"veya" ve "ve" kullanımına dikkat edin, btw, || ile karşılaştırıldığında farklı ve çok düşük önceliğe sahipler. ve &&. Bazı açıklamalar için blog.jayfields.com/2007/08/… adresine bakın .
Mike Woodhouse

Sorudaki "koku" ile ilgili bazı posterlere katılıyorum, ancak bana göre bu daha çok yakut yol.
Jonke

6
Öncelik orBurada herhangi parens gerektirmez ve deneyimli bir Rubyist doğal tamamen okuyacaktır. Hiç ısırması sadece insanlar ||karşı or:) Perl programlanmış hiç insanlardır
ephemient

1
Endişelenmeniz gereken tek zaman || VEYA önceliğine karşı atamada, boole kontrolünde değil. Bununla birlikte, kelimenin düşük önceliği hata kontrolü için çok kullanışlı olabilir.
Robert K

3
Daha val && val == 0iyi olduğunu düşünüyorum .
Nakilon

35

Sonunda soru işareti olan yöntem adlarını gerçekten seviyorsanız:


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

Çözümünüz, diğer çözümlerden birkaçı gibi gayet iyi.

Ruby, dikkatli değilseniz, her şeyi yapmanın güzel bir yolunu aramanızı sağlayabilir.


32

Ruby 2.3.0'dan itibaren, güvenli gezinme operatörünü ( &.) Numeric#nonzero?. &.döndüren nilörnek olsaydı nilve nonzero?- sayı ise 0:

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

Veya postfix:

do_something unless val&.nonzero?

Bu müthiş yeni ve modern bir cevaptı. Ayrıca, burada neden kullanıldığına dair harika bir makale var: Ruby'de Güvenli Navigasyon Operatörü (&.)
Michael Gaskill

1
Çok kısa, ama yorum unless val&.nonzero?yapmazsak, bunun "değer sıfır mı yoksa sıfır mı" anlamına geldiğini anlamam biraz zaman alacaktı
Stefan

1
@Stefan, kabul etti. Bunu üretim kodunda kendim kullanmazdım. Tamamlayıcılık için dahil ettim. Tersi tamamen okunabilir - do_something if val&.nonzero?(yani sıfır valdeğilse nilve sıfır değilse).
ndnenkov

29

Öncelikle, bu belirli durumu kontrol etmenin en kısa yolu olduğunu düşünüyorum.

İkincisi, bana göre bu, tasarımınızda olası bir kusuru gösteren bir kod kokusu. Genel olarak sıfır ve sıfır aynı anlama gelmemelidir. Mümkünse, bu koda ulaşmadan önce, ya yöntemin başında ya da başka bir mekanizmada kontrol ederek, değerin sıfır olma olasılığını ortadan kaldırmaya çalışmalısınız.

Bunu yapmak için tamamen meşru bir nedeniniz olabilir, bu durumda kodunuzun iyi olduğunu düşünüyorum, ancak en azından mümkünse sıfır kontrolünden kurtulmayı düşünürüm.


4
Kod kokusu konusunda çok haklısınız! +1 NullObject kalıbına bakmayı düşünebilirsiniz en.wikipedia.org/wiki/Null_Object_pattern
abyx

9

Object.nil'i kullanabilir misiniz? sıfır için özel olarak test etmek (ve yanlış ve sıfır arasında kalmamak). Bir yöntemi Object'e de maymun yamalayabilirsiniz.

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

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

İş arkadaşlarınızın Nesne değişikliklerini izlemesi zor olduğundan ve kodunuzu başkaları için öngörülemez hale getirebileceğinden bu önerilmez.


Nesne yerine Numeric sınıfını değiştirirdim.
epochwolf

6
epochwolf, bunu Numeric sınıfına koyarsanız, nil?her zaman yanlış döndürür. nil?yalnızca NilClass üzerinde true döndürür.
Ryan McGeary

Sen metodu uygulamak olabilir Object, NilClassve Numeric. Objectdönecekti false, NilClassdönecekti trueve Numericdönecekti zero?.
Stefan

6

nil.to_i sıfır döndürür, bu yüzden bunu sık sık yaparım:

val.to_i.zero?

Bununla birlikte, val, #to_i'ye yanıt vermeyen bir nesne ise bir istisna alırsınız.


referans için: Scott'ın cevabı ve @AndrewGrimm bunun hakkında ne söyledi:"5".to_i == 5, but you're more or less right. Clever but doesn't actually work
Paul van Leeuwen

4

Kodunuzun yanlış olduğuna inanıyorum; : bir bakıma bu testte üç değerler için olacak nil, falseve sıfır. Bunun nedeni, !valifadenin yanlış olan tüm değerler için doğru olmasıdır, Ruby'de nilve false.

Şu anda bulabileceğim en iyi şey

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

Elbette ki pek akıllıca değil, ama (çok) açık.


muhtemelen söz konusu değişkenin bir Sayısal olduğunu varsayabilirsiniz. Bunun Boole mu yoksa Sayısal mı olduğunu bilmiyorsanız, kodda daha büyük problemler vardır.
Mike Deck

4

Benim çözümüm de Koşullar hariç Ayrıntılandırmaları kullanıyor.

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 bunu öznitelik sorgulama yöntemleriyle yapar; burada false ve nil'e ek olarak, 0 ve "" de false olarak değerlendirilir.

if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation

Bununla birlikte, aleyhte payına sahiptir. http://www.joegrossberg.com/archives/002995.html


Bağlantı çalışmıyor. Yöntemi merak ediyorum #attributeçünkü böyle bir şey bulamıyorum.
mrzasa

Rails / ActiveRecord'un anında eklediği bir şeydir. Müşterinin bir ad alanı varsa, ad? adın boş veya sıfır olup olmadığını kontrol etmek için otomatik olarak eklenir. Bkz api.rubyonrails.org/classes/ActiveRecord/Base.html - 'öznitelik sorgulama yöntemleri' bölümünü arayın
Gishu

2

Mümkün olduğunca deyimsel olmak için bunu öneririm.

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

Çünkü:

  • Sıfır mı kullanıyor? yöntem.
  • || ye tercih edilen "veya" operatörünü kullanır.
  • Bu durumda gerekli olmayan parantezler kullanmaz. Parantezler yalnızca belirli operatörlerin önceliğini geçersiz kılmak gibi bir amaca hizmet ettiklerinde kullanılmalıdır.

1
Bunun tam anlamıyla 7 yıl öncesine ait olduğunu bilmeme rağmen, bunun için olumsuz oy verdim: github.com/bbatsov/ruby-style-guide#no-and-or-or
Devon Parsons

2

Kısa ve net

[0, nil].include?(val)


2
: Ayrıca ters Canval.in? [0,nil]
mahemoff

1
@mahemoff kesinlikle bunun için en iyi deyim!
intmarinoreturn0

@mahemoff daha iyi kullanım içerir? ref: stackoverflow.com/questions/28272550/…
Lakhani Aliraza

İyi nokta, ama şimdi onu modern Ruby'de ve içinde çalıştırdım. aslında tek bir çağrı için daha hızlıydı ve 1000 çağrı için oldukça benzerler. Her ikisi de son derece hızlı, çok az uygulamanın imo'yu etkilemesine yetecek kadar. gist.github.com/mahemoff/7232648e1ccb9d23e0f4670913400“
mahemoff

2

En kısa ve en iyi yol olmalı

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

İçin val&.>(0) ne zaman val nil yana nil döner> temelde Ruby için yanlış eşit sıfırdır, aynı zamanda bir yöntemdir. Ne zaman yanlış döner val == 0.


3
Neye göre en kısası?, Neyden en iyi yol?
Sebastian Palma

0

Bunu bir "var mı?" yöntem, daha sonra çeşitli sınıflarda farklı şekilde uygulayabilirim. Yani Array için "nedir?" "beden> 0" anlamına gelir; Fixnum için "self! = 0" anlamına gelir; String için "self! = ''" anlamına gelir. NilClass elbette "eşittir?" sadece sıfır olarak dönüyor.


0

İsterseniz kullanabilirsiniz case:

 case val with nil, 0
      # do stuff
 end

O zaman işe ===yarayan her şeyi kullanabilirsiniz , ki bu bazen güzeldir. Veya bunun gibi bir şey yapın:

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

Tam olarak iyi bir OOP değil, ama çok esnek ve işe yarıyor. Benim ifsilerim genellikle casezaten biter .

Tabii ki Enum.any?/ Enum.include?türden de işe yarar ... gerçekten şifreli olmayı seviyorsanız:

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

Yapılması gereken doğru şey elbette bir yöntem veya işlev tanımlamaktır. Ya da aynı şeyi birçok değerle yapmanız gerekiyorsa, bu güzel yineleyicilerin bir kombinasyonunu kullanın.


0

Gerçekten Raylar gibi blank?şeyler için bu tür yöntemle, ancak dönmeyecek trueiçin0 . Böylece yönteminizi ekleyebilirsiniz:

def nil_zero? 
  if respond_to?(:zero?) 
    zero? 
  else 
    !self 
  end 
end 

Ve bazı değerlerin sıfır mı yoksa 0 mı olduğunu kontrol edecek:

nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false

if val.nil_zero?
  #...
end

0

Maymun bir sınıfa yama yapmak yerine, iyileştirmeler kullanabilirsiniz. Ruby 2.1'den başlayarak . İyileştirmeler maymun yamasına benzer; bu, sınıfı değiştirmenize izin verir, ancak değişiklik, onu kullanmak istediğiniz kapsam ile sınırlıdır.

Bu kontrolü bir kez yapmak istiyorsanız, bu aşırıdır, ancak kendinizi tekrarlıyorsanız, maymun yamasına harika bir alternatiftir.

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

Kapsamı dosyaya eklenmek üzere son dakikada ayrıntılandırmalar değiştirildi . Yani daha önceki örnekler bunu göstermiş olabilir ve bu işe yaramayacaktır.

class Car
  using NilOrZero
end

0

Bu çok kısa:

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

Bu sürece tedavi sakıncası olarak çalışıyor falseaynı nil. Üzerinde çalıştığım projelerde, bu ayrım sadece arada bir önem taşıyor. Geri kalan zamanlarda kişisel olarak atlamayı .nil?ve biraz daha kısa kod kullanmayı tercih ederim .

[ Güncelleme : Artık bu tür şeyler yazmıyorum. Çalışıyor ama çok şifreli. Yaptığım birkaç yeri değiştirerek suçlarımı düzeltmeye çalıştım.]

Bu arada, söz gelimi bir dizge ise .zero?bir istisna yarattığı için kullanmadım val. Ama .zero?durumun böyle olmadığını bilirseniz iyi olur.


[edited]valSıfır olsaydı bu ifadenin değerlendirileceğini nil == 0(ve böylece geri döneceğini false) düşündüm . Yine de öyle görünüyor ki aslında işe yarıyor, ancak çok okunabilir olduğunu düşünmüyorum.
omnikron

Şimdi buradaki yaklaşımımın sadece birkaç karakteri kurtarmak için fazla şifreli olduğuna inanıyorum ve bugünlerde böyle yazmam. Bu yüzden herhangi bir olumlu oy beklemiyorum, ancak işe yarayan bir cevap için verilen olumsuz oylara biraz şaşırdım (tadı şüpheli olmasına rağmen) ...
antinome

0

Bu, sıfır ve sıfır için doğru olarak değerlendirilir: nil.to_s.to_d == 0



-1

Başka bir çözüm:

if val.to_i == 0
  # do stuff
end

1
Bu yalnızca val bir tamsayı veya sıfır ise çalışır; 0.5.to_i == 0, any_string.to_i == 0, vb.
Zach Langley

"5".to_i == 5ama az ya da çok haklısın. Zekice ama aslında işe yaramıyor.
Andrew Grimm

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

3
-1: Ya içindeki değerin valtutulması gerekiyorsa? Bu yöntemle giriş verilerini bozuyorsunuz ve sıfır veya sıfır olup olmadığını kontrol etmenin daha iyi, daha az yıkıcı yolları var.
Platinum Azure

3
Peki ya (val || 0) .zero?
timkay
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.