2008-10-16 2 views
63

Я ищу краткий способ проверить значение, чтобы узнать, равен ли он нулю или нулю. В настоящее время я делаю что-то вроде:Лучшая рубиновая идиома для «ноль или ноль»

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

Но это кажется очень неуклюжим.

+1

Что должно произойти, если вал равно `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-priorence-of-and-which.html для некоторых замечаний. – 2008-10-16 19:26:04

+0

Я согласен с некоторым плакатом «запаха» в вопросе, однако для меня это больше рубиновый путь. – Jonke 2008-10-16 20:20:29

+6

Приоритет `или` здесь не требует никаких парсеров и будет полностью читаться опытным рубистом. Единственные люди, которых когда-либо кусали `` `` `` `` `` `` `или`, - это люди, которые никогда не программировали Perl :) – ephemient 2008-10-16 21:42:22

4

Я считаю, что код неправильный; он будет фактически проверять три значения: nil, false, и ноль. Это связано с тем, что выражение !val истинно для всех значений, которые являются ложными, что в Ruby составляет nil и false.

Лучшее, что я могу придумать прямо сейчас

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

Что, конечно, не очень умный, но (очень) ясно.

+0

, вы можете предположить, что переменная, о которой идет речь, является числовой. Если вы даже не знаете, есть ли в Boolean или Numeric больше проблем в коде. – 2008-10-16 17:32:45

+0

Я бы использовал .nil? not == nil – RichH 2008-10-16 21:08:17

29

Прежде всего, я думаю, что речь идет о наиболее сжатом способе вы можете проверить это конкретное условие.

Во-вторых, для меня это запах кода, который указывает на потенциальный недостаток вашего дизайна. Как правило, ноль и ноль не должны означать одно и то же. Если возможно, вы должны попытаться исключить возможность того, что val будет равен нулю, прежде чем вы нажмете этот код, либо проверив это в начале метода, либо каким-либо другим механизмом.

Возможно, у вас вполне законная причина сделать это, и в этом случае я думаю, что ваш код хорош, но я бы хотя бы подумал о том, чтобы попытаться избавиться от проверки nil, если это возможно.

+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

Я бы изменил числовой класс, а не объект. – epochwolf 2008-11-05 00:24:22

+6

epochwolf, если вы поместите это в числовой класс, тогда `nil?` Всегда будет возвращать false. `nil?` возвращает true только на NilClass. – 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

Ссылка не работает. Мне интересен метод `# attribute`, потому что я не могу найти ничего подобного. – 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

имею дело с этим, определяя "есть?" метод, который затем я могу реализовать по-разному на разных классах. Итак, для Маре, «есть?» означает «размер> 0»; для Fixnum это означает «self! = 0»; для String это означает «self! =». NilClass, конечно, определяет «есть?» как только возвращающ ноль.

2

Чтобы быть как можно более идиоматичным, я бы предложил это.

if val.nil? or val == 0 
    # Do something 
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 

Это не совсем хороший ООП, но он очень гибкий и работает. Мой if s обычно заканчивается как case s в любом случае.

Конечно 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? 

Однако, вы получите исключение, если Допустимы когда-либо объект, который не respond_to #to_i.

0

Мне очень нравится Rails blank? метод для таких вещей, но он не вернется true для 0. Таким образом, вы можете добавить свой метод:

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 

Он работает до тех пор, вы не против обработки false так же, как nil. В проектах, над которыми я работал, это различие имеет значение только время от времени. В остальное время я лично предпочитаю пропускать .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 если экземпляр был nil и nonzero? - если номер был 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) возвращает ноль, когда вал равен нулю, так как> в основном также метод, ноль равно ложь в рубин. Он возвращает false, когда val == 0.

0

Это имеет значение верно для ноль и ноль: nil.to_s.to_d == 0

Смежные вопросы