Проверка, если переменная не ноль и не ноль в ruby


271

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

if(discount != nil && discount != 0) 
  ...
end

Есть лучший способ сделать это?


1
Вероятно, потому что это точная копия stackoverflow.com/questions/209495/… .
Дэвид Нехм

1
Что делать, если discountложь?
Эндрю Гримм

1
Я думаю, discount.in? [0, nil]что более чистый способ возможен
intmarinoreturn0

Ответы:


428
разве что discount.nil? || скидка == 0
  # ...
конец

31
Используйте 'или' вместо ||
Орион Эдвардс

93
@ orion-edwards почему?
НАРКОЗ

39
Использование «или» опасно. 'or' имеет более низкий уровень присутствия операторов, чем '=', поэтому следующее имеет неожиданное поведение: a = false или true #a ложно после этого оператора
Tom G

20
@xiy в настоящее время руководство рекомендует делать вид или и и не существует (|| это или && и?)
user3125280

67
Текущие "Ruby Style Guide" стоит The and and or keywords are banned. It's just not worth it. Always use && and || instead.. И это правильно по причинам Дэвида и Тома.
Андре Фигейредо

40
class Object
  def nil_zero?
    self.nil? || self == 0
  end
end

# which lets you do
nil.nil_zero? # returns true
0.nil_zero?   # returns true
1.nil_zero?   # returns false
"a".nil_zero? # returns false

unless discount.nil_zero?
  # do stuff...
end

Остерегайтесь обычных заявлений об отказе от ответственности ... великой власти / ответственности, исправлений обезьян, ведущих на темную сторону и т. Д.


28

хорошо, через 5 лет прошло ....

if discount.try :nonzero?
  ...
end

Важно отметить, что tryон определен в геме ActiveSupport, поэтому он недоступен в обычном ruby.


7
Обратите внимание, что это специфичный для рельсов ответ. Ванильный рубин не имеет tryметода.
Том Лорд

Верный. Хотя это больше похоже на спецификацию ActiveSupport, которая намного легче и широко используется, чем полные рельсы. В любом случае, ответ @ ndn верный.
переписано

Отредактировано для использования безопасной навигации
переписано

1
Ответ теперь дублирует stackoverflow.com/a/34819818/1954610 ... Я думаю, что есть смысл оставить его так, tryчтобы показать альтернативный вариант (именно поэтому он был отклонен в первую очередь!), При условии, что это ясно для читатель, который ActiveSupportне ванильный рубин.
Том Лорд

Точка занята, ответ откатан.
переписано

27
если только [nil, 0] .include? (скидка) 
  # ...
конец

13
Прекрасный? Да. Удобочитаемый? На самом деле, нет.
Эль Ниндзя Трепадор

1
Я нахожу это прекрасно читаемым, и я бы предпочел его новому классу. Отлично сработано.
colincr

Наиболее рубиновый подход к обработке двух условий.
Югендран

23

Начиная с версии 2.3.0, вы можете комбинировать оператор безопасной навигации ( &.) с Numeric#nonzero?. &.возвращает, nilесли экземпляр был nilи nonzero?- если число было 0:

if discount&.nonzero?
  # ...
end

Или постфикс:

do_something if discount&.nonzero?

"foo"&.nonzero? # => NoMethodError: undefined method 'nonzero?' for "foo":String.... Это не безопасно использовать на произвольных объектах.
Том Лорд

2
@TomLord, как указано в предыдущем комментарии, не предназначался для работы с произвольными объектами. Вместо этого это касается случая, когда у вас есть что-то, что вы знаете, должно быть числом, но также может быть nil.
ndnenkov

Я хотел бы прояснить этот факт в ответе, вместо того, чтобы кто-то прочитал это и не заметил отказ от комментариев в комментариях.
Том Лорд

@TomLord, это указано в ответе " nonzero?- если номер был 0" . Также необходимость проверять, возникает ли совершенно произвольный объект 0крайне редко по сравнению с тем, чтобы проверять число, которое может или не может быть nil. Следовательно, это почти подразумевается. Даже если кто-то делает противоположное предположение, он сразу же поймет, что происходит, когда попытается его выполнить.
ndnenkov


15

Вы могли бы сделать это:

if (!discount.nil? && !discount.zero?)

Здесь важен порядок, потому что если discountесть nil, то у него не будет zero?метода. Оценка Руби по короткому замыканию должна препятствовать тому, чтобы он пытался оценить discount.zero?, однако, если discountесть nil.


11

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

"".to_i.zero? => true
nil.to_i.zero? => true

осторожно: 0.1.to_i == 0
Саймон Б.


2

Вы можете воспользоваться NilClassпредоставленным #to_iметодом, который будет возвращать ноль для nilзначений:

unless discount.to_i.zero?
  # Code here
end

Если это discountмогут быть дробные числа, вы можете использовать #to_fвместо них, чтобы предотвратить округление числа до нуля.


Разве это не то же самое, что ответ @ oivoodo?
Кэри Свовеланд

Не работает для произвольных объектов . "".to_i == "foo".to_i == "0".to_i == 0, Ваш метод сделает все виды непреднамеренных приведения типов. Он также потерпит неудачу, NoMethodErrorесли discountне отвечает to_i.
Том Лорд

2
def is_nil_and_zero(data)
     data.blank? || data == 0 
end  

Если мы передадим "", он вернет false, тогда как пусто? возвращает истину. То же самое в случае, когда data = false blank? возвращает true для nil, false, empty или строки пробела. Так что лучше использовать бланк? метод, чтобы избежать пустой строки.


1
blank?это метод для рельсов, недоступный в ванильном рубине.
Том Лорд

Ты прав!! Я думал, что это связано с тегом "ROR", поэтому размещен здесь. Моя ошибка. Это не сработает в ванильном рубине.
Сарой

1

При работе с записями в базе данных мне нравится инициализировать все пустые значения с 0, используя помощник по миграции:

add_column :products, :price, :integer, default: 0

0

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



0

Я предпочитаю использовать более чистый подход:

val.to_i.zero?

val.to_iвернет, 0если val является nil,

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


-1

Альтернативное решение - использовать уточнения, например:

module Nothingness
  refine Numeric do
    alias_method :nothing?, :zero?
  end

  refine NilClass do
    alias_method :nothing?, :nil?
  end
end

using Nothingness

if discount.nothing?
  # do something
end

-7

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

if discount != 0
end

8
Было бы оценить, trueесли бы были скидки nil.
Эндрю Гримм
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.