Лучшая идиома ruby для "nil or zero"


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

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

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

20 67

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 выражение справедливо для всех значений, которые являются ложными, что в Ruby nil и 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, nil].include?(val)

Я имею дело с этим, определяя "есть?"метод, который я могу затем реализовать по-разному на различных классах. Так что для массива, " есть?"означает" размер>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ы, как правило, в конечном итоге, как cases в любом случае.

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

это значение равно true для nil и нуля:nil.to_s.to_d == 0

это очень лаконично:

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

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

[обновление: Я больше ничего такого не пишу. Это работает, но слишком загадочно. Я попытался исправить свои проступки, изменив несколько мест, где я это сделал оно.]

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

другое решение:

if val.to_i == 0
  # do stuff
end
val ||= 0
if val == 0
# do something here
end