Вопрос

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

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

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

Это было полезно?

Решение

Объекты имеют ноль? метод.

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?

Вы можете использовать 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

Это не рекомендуется, так как изменения в Object трудно отследить коллегам, и это может сделать ваш код непредсказуемым для других.

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

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

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

Что конечно не очень умно, но (очень) понятно.

nil.to_i возвращает ноль, поэтому я часто делаю это:

val.to_i.zero?

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

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

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

Коротко и ясно

[0, nil].include?(val)

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

Вы можете использовать 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в любом случае.

Конечно Enum.any?/Enum.include? тоже вроде работает...если вам нравится быть по-настоящему загадочным:

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

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

Мне очень нравится Рельс 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? было бы хорошо, если бы вы знали, что это не так.

Это оценивается как true для нуля и нуля: nil.to_s.to_d == 0

unless (val || 0).zero?

    # do stufff

end

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

if val.to_i == 0
  # do stuff
end
val ||= 0
if val == 0
# do something here
end
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top