Лучшая идиома ruby для "nil or zero"
Я ищу краткий способ проверить значение, чтобы увидеть, если это ноль или ноль. В настоящее время я делаю что-то вроде:
if (!val || val == 0)
# Is nil or zero
end
но это кажется очень неуклюжим.
20 ответов:
объекты шь? метод.
if val.nil? || val == 0 [do something] end
или только одна инструкция:
[do something] if val.nil? || val == 0
Если вам действительно нравятся имена методов с вопросительными знаками в конце:
if val.nil? || val.zero? # do stuff end
ваше решение в порядке, как и некоторые другие решения.
Ruby может заставить вас искать красивый способ сделать все, если вы не будете осторожны.
во-первых, я думаю, что это самый краткий способ, которым вы можете проверить это конкретное условие.
во-вторых, для меня это запах кода, который указывает на потенциальный недостаток в вашем дизайне. Как правило, ноль и ноль не должны означать одно и то же. Если возможно, вы должны попытаться исключить возможность того, что val будет равен нулю, прежде чем вы нажмете этот код, либо проверив это в начале метода, либо какой-либо другой механизм.
У вас может быть совершенно законный причина сделать это, и в этом случае я думаю, что ваш код хорош, но я бы по крайней мере подумал о том, чтобы попытаться избавиться от нулевой проверки, если это возможно.
начиная с Ruby 2.3.0, вы можете объединить оператора безопасной навигации (
&.
) СNumeric#nonzero?
.&.
возвращаетnil
если экземпляр былnil
иnonzero?
- если число было0
:unless val&.nonzero? # Is nil or zero end
или постфикс:
do_something unless val&.nonzero?
вы можете использовать объект.Нил? чтобы проверить на ноль конкретно (и не попасть между false и nil). Вы можете обезьяна-патч метод в объект, а также.
class Object def nil_or_zero? return (self.nil? or self == 0) end end my_object = MyClass.new my_object.nil_or_zero? ==> false
Это не рекомендуется, так как изменения объекта трудно отслеживать коллегам и может сделать ваш код непредсказуемым для других.
nil. to_i возвращает ноль, поэтому я часто делаю это:
val.to_i.zero?
однако, вы получите исключение, если val когда-либо объект, который не respond_to #to_i.
Я считаю, что ваш код неверен; он будет на самом деле тест для трех значений:
nil
,false
, и ноль. Это потому что!val
выражение справедливо для всех значений, которые являются ложными, что в Rubynil
иfalse
.лучшее, что я могу придумать прямо сейчас
if val == nil || val == 0 # do stuff end
что конечно не очень умно, но (очень) понятно.
мое решение также использует уточнения, минус условные обозначения.
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 и "" также оцениваются как false.
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
потому что:
- он использует ноль? метод.
- он использует оператор "или", который предпочтительнее ||.
- он не использует скобки, которые в данном случае не нужны. Круглые скобки должны использоваться только тогда, когда они служат какой-то цели, например, наиглавнейшая приоритет определенных операторов.
самый короткий и лучший способ должен быть
if val&.>(0) # do something end
на
val&.>(0)
он возвращает nil, когда val равен nil, так как > в основном также является методом, равным false в ruby. Она возвращает false, когдаval == 0
.
Я имею дело с этим, определяя "есть?"метод, который я могу затем реализовать по-разному на различных классах. Так что для массива, " есть?"означает" размер>0"; для Fixnum это означает " сам != 0"; для строки это означает " сам != "" . NilClass, конечно, определяет "есть?- как только что вернувшийся Нил.
можно использовать
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
ы, как правило, в конечном итоге, какcase
s в любом случае.конечно
Enum.any?
/Enum.include?
это тоже работает ... если вы хотите получить действительно загадочное:if [0, nil].include? val #do stuff end
правильно, конечно, определить a метод или функция. Или, если вам нужно сделать то же самое со многими значениями, используйте комбинацию этих хороших итераторов.
мне очень нравятся рельсы
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
вместо того, чтобы обезьяна исправлять класс,вы можете использовать уточнений начиная с 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
усовершенствования были изменены в последние минута, которая будет определена в файл. Поэтому более ранние примеры, возможно, показали это, что не будет работать.
class Car using NilOrZero end
это очень лаконично:
if (val || 0) == 0 # Is nil, false, or zero. end
это работает до тех пор, пока вы не возражаете лечения
false
аналогичноnil
. В проектах, над которыми я работал, это различие имеет значение только время от времени. В остальное время я лично предпочитаю пропустить.nil?
и имеют немного более короткий код.[обновление: Я больше ничего такого не пишу. Это работает, но слишком загадочно. Я попытался исправить свои проступки, изменив несколько мест, где я это сделал оно.]
кстати, я не использую
.zero?
так как это вызывает исключение, еслиval
- это, скажем, строку. Но.zero?
будет хорошо, если вы знаете, что это не так.