2008-10-16 31 views
63

我正在尋找一個簡明的方法來檢查一個值,看它是零還是零。目前我做的是這樣的:「零或零」的最佳紅寶石成語

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

但這似乎很笨拙。

+1

應該發生什麼,如果VAL等於`FALSE`? – 2010-09-29 06:21:04

回答

61

對象有一個nil? method

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

或者,僅僅用一個指令:

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

小心使用「或」和「和」,順便說一下,它們具有不同的且非常低的優先級與||相比和&&。請參閱http://blog.jayfields。com/2007/08/ruby​​-operator-precedence-of-and-which.html的一些評論。 – 2008-10-16 19:26:04

+0

我同意這個問題中的「嗅覺」的一些海報,但對我來說這更像是一種紅寶石般的方式。 – Jonke 2008-10-16 20:20:29

+6

`或`的優先級在這裏不需要任何parens,並且會完全自然地讀給一位經驗豐富的Rubyist。唯一被`||`與`或`咬過的人是從未編程過Perl的人:) – ephemient 2008-10-16 21:42:22

4

我相信你的代碼是不正確的;它實際上會測試三個值:nil,false和零。這是因爲!val表達式適用於所有值爲false的值,在Ruby中爲nilfalse

我可以想出現在最好的是

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

這當然不是很聰明,但(很)清楚。

+0

你或許可以假定所討論的變量是一個數字。如果你甚至不知道它是布爾型還是數值型,那麼代碼中存在更大的問題。 – 2008-10-16 17:32:45

+0

我會用.nil? not ==零 – RichH 2008-10-16 21:08:17

29

首先,我認爲這是關於您可以檢查特定條件的最簡潔的方式。

其次,對我來說,這是一種代碼氣味,表明您的設計中存在潛在的缺陷。通常零和零不應該意味着同樣的事情。如果可能的話,您應該嘗試消除在您打開此代碼之前val不可能爲零的可能性,無論是通過檢查方法的開頭還是其他機制。

你可能有一個完全合法的理由來做到這一點,在這種情況下,我認爲你的代碼是好的,但我至少會考慮嘗試擺脫零檢查,如果可能的話。

+4

非常正確的代碼氣味! +1 可能考慮查看NullObject模式http://en.wikipedia.org/wiki/Null_Object_pattern – abyx 2009-11-06 19:57:53

9

您可以使用Object.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 

不建議作爲修改對象是困難的同事跟蹤,並且可以使你的代碼不可預知他人。

+0

我會修改Numeric類而不是Object。 – epochwolf 2008-11-05 00:24:22

+6

epochwolf,如果你把它放在Numeric類上,那麼`nil?`總是返回false。 `nil?`只在NilClass上返回true。 – 2009-01-26 02:21:58

+0

您可以在`Object`,`NilClass`和`Numeric`中實現該方法。 `Object`會返回`false`,`NilClass`會返回`true`,`Numeric`會返回`zero?`。 – Stefan 2017-06-27 05:25:13

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

+0

鏈接不起作用。我很好奇`#屬性`的方法,因爲我找不到那樣的東西。 – mrzasa 2012-08-07 07:00:07

+0

這是Rails/ActiveRecord實時添加的東西。如果客戶有名稱字段,名稱?會自動添加以檢查名稱是空白還是零。請參閱http://api.rubyonrails.org/classes/ActiveRecord/Base.html - 搜索「屬性查詢方法」部分 – Gishu 2012-08-07 08:48:21

0

我定義處理這一個 「是什麼?」方法,然後我可以在不同的類上實現不同的方法。所以對於Array而言,「是嗎?」意味着「大小> 0」;對於Fixnum來說,它意味着「self!= 0」;對於字符串,它的意思是「self!=''」。當然,NilClass定義「是?」只是返回零。

2

爲了儘可能地道,我建議這樣做。

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

因爲:

  • 它使用的零?方法。
  • 它使用「或」運算符,這比||更好。
  • 它不使用括號,在這種情況下不需要使用括號。括號只能用於某些目的時,如覆蓋某些運算符的優先級。
-3
val ||= 0 
if val == 0 
# do something here 
end 
30

如果你很喜歡在結尾帶有問號的方法名稱:

 

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

你的解決方案是好的,因爲有一些其他的解決方案。

如果你不小心,Ruby可以讓你搜索一個可以做所有事情的好方法。

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

當然Enum.any?/Enum.include?樣的作品太...如果你想獲得真正的神祕:

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

做的正確的事情當然是定義一個方法或函數。或者,如果你必須用許多值來做同樣的事情,那麼使用這些好的迭代器的組合。

-2

另一種解決方案:

if val.to_i == 0 
    # do stuff 
end 
5

nil.to_i返回零,所以我經常這樣做:

val.to_i.zero? 

然而,你會得到一個異常,如果val爲曾經的對象沒有的respond_to #to_i。

0

我真的很喜歡Rails blank?這種方法,但它不會爲0返回true。所以,你可以添加你的方法:

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

它會檢查,如果某個值是零或0:

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

if val.nil_zero? 
    #... 
end 
-1

這是非常簡潔:

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

它的工作原理,只要你不介意對待falsenil相同。在我所從事的項目中,這種區別只是偶爾發生的。剩下的時間我個人更喜歡跳過.nil?並且代碼略短。

[更新:我不再寫這種東西了。它的作品,但太神祕了。我試圖通過改變我所做的幾個地方來糾正我的錯誤。]

順便說一下,我沒有使用.zero?,因爲如果val是字符串,這會引發異常。但如果你知道情況並非如此,.zero?會很好。

0

取代猴子修補類,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 
10

紅寶石2.3.0開始,你可以用Numeric#nonzero?結合安全導航操作符(&.)。 &.返回nil如果實例是nilnonzero? - 如果數量爲0

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

或後綴:

do_something unless val&.nonzero? 
1

簡短清晰

[0, nil].include?(val)

2

的最佳捷徑應該是

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

對於val&.>(0) 當val爲零,因爲>基本上也是一個方法,零等於在紅寶石假它返回零。它在val == 0時返回false。

0

這個計算結果爲true的零和零:nil.to_s.to_d == 0