Перевірка, чи змінна не є нульовою та не нульовою в рубіні


271

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

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

Чи є кращий спосіб зробити це?


1
Можливо, тому, що це точна копія stackoverflow.com/questions/209495/… .
Девід Неме

1
Що робити, якщо discountпомилково?
Ендрю Грімм

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

Відповіді:


428
хіба знижка.nil? || знижка == 0
  # ...
кінець

31
Використовуйте "або" замість ||
Оріон Едвардс

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

39
Використання "або" небезпечно. 'або' має меншу презентаційність оператора, ніж '=', тому наступне має несподівану поведінку: a = false або true #a є помилковим після цього твердження
Tom G

20
@xiy в даний час посібник рекомендує робити вигляд, або і не існує (|| це чи && і?)
user3125280

67
Поточний "Посібник зі стилем Ruby" 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, тому він недоступний у звичайному рубіні.


7
Зауважте, що це відповідь на конкретні рейки . Вабільний рубін не має tryметоду.
Том Лорд

Правильно. Хоча він більше схожий на ActiveSupport, який набагато легший і широко використовується залежність, ніж повні рейки. У будь-якому випадку відповідь @ ndn є правильною.
переписано

Відредаговано для використання безпечної навігації
переписано

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

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

27
якщо [нуль, 0]. включити? (знижка) 
  # ...
кінець

13
Гарний? Так. Читання? Не зовсім.
El Ninja Trepador

1
Я вважаю це ідеально читабельним, і я вважаю за краще це перед новим класом. Молодці.
colincr

Найбільш рубійний підхід до вирішення двох умов.
Югендран

23

З Ruby 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
Саймон Б.

3
if discount and discount != 0
  ..
end

оновлення, це буде falseдляdiscount = false


2

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

unless discount.to_i.zero?
  # Code here
end

Якщо discountможуть бути дробові числа, ви можете використовувати #to_fнатомість, щоб запобігти округленню числа до нуля.


Це не те саме, що відповідь @ oivoodo?
Cary Swoveland

Не працює для довільних об'єктів . "".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  

Якщо ми передамо "", вона поверне помилкову, тоді як порожню? повертає правду. Той самий випадок, коли дані = помилкові порожні? повертає true для нуля, false, порожнього чи рядка пробілів. Тож краще використовувати бланк? метод, щоб уникнути порожнього рядка.


1
blank?є специфічним для рейок способом і не доступний у вабільному рубіні.
Том Лорд

Ви праві!! Я подумав, що це пов'язано з тегом "ror", розміщеним тут. Моя помилка. Це не буде працювати у ванільному рубіні.
Сарой

1

У роботі з записом бази даних я люблю ініціалізувати всі порожні значення з 0, використовуючи помічник міграції:

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

0

Ви можете ініціалізувати знижку до 0 до тих пір, поки гарантовано, що ваш код не намагатиметься використовувати його до ініціалізації. Це, мабуть, зніме одну перевірку, я не можу придумати нічого іншого.



0

Я вважаю за краще використовувати більш чистий підхід:

val.to_i.zero?

val.to_iповерне a, 0якщо val - a 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.