Ruby: если переменная vs, если variable.nil?

11

Я новичок в Ruby, и я был удивлен, когда узнал, что все объекты истинны, кроме nil и false. Даже 0 это правда.

Хорошая особенность этого свойства языка в том, что вы можете написать:

if !variable
  # do stuff when variable is nil
end

Мои коллеги, которые являются более опытными разработчиками Ruby, настаивают, чтобы я выбрал это вместо использования .nil? вот так:

if variable.nil?
  # do stuff when variable is nil
end

Однако я считаю, что последний вариант лучше по двум причинам: 1. Я думаю, что он более объектно-ориентирован, особенно в языке, подобном Ruby, где все является обменом объектами и сообщениями. 2. На мой взгляд, он более читабелен, даже если он менее компактен.

Я делаю ошибку "новичка" здесь?

Хавьер Холгера
источник
4
Вы тестируете на ноль? или ложное значение?
Я тестирую на ноль. В основном, если переменная равна нулю, я что-то делаю (или нет)
Хавьер Холгуэра
3
Если вы тестируете на ноль, почему вы хотите, чтобы тест на ложь также входил в этот блок?
Согласитесь, я указал, что в качестве еще одной причины отдать предпочтение .nil? Но они настаивали на том, что «if variable do x» более идиоматичен, чем «if variable.nil? Do x», и предпочтительнее, когда вы знаете, что переменная не является булевой
Хавьер Холгера

Ответы:

17

Напиши, что ты имеешь в виду. Имею ввиду то, что ты пишешь.

Пройдем другой тест. .vowel?

if char == 'a'
   # do stuff
end

против

if char.vowel?
   # do stuff
end

Теперь очевидно, что они не делают то же самое. Но если вы только ожидая , charчтобы быть aили bон будет работать. Но это запутает следующего разработчика - второй блок будет введен для условий, где [eiou]также есть char . Но ведь aэто будет работать правильно.

Да, это тот случай, когда nilи falseявляются единственными ложными значениями в Ruby. Однако, если вы проверяете nil, проверяя nil || falseэто, это не то, что вы имеете в виду.

Это означает, что следующий разработчик (который оказывается убийцей сумасшедшего топора, который знает ваш домашний адрес) прочтет код и задастся вопросом, зачем falseему туда идти.

Напишите код, который передает именно то , что вы имеете в виду.

Пер Лундберг
источник
3

Учтите следующее:

response = responses.to_a.first

Это вернет первый элемент responses, или nil. Тогда потому что условные операторы обрабатывают nilкак falseмы можем написать:

response = responses.to_a.first
if response
  # do something ('happy path')
else
  # do something else
end

Который является более читабельным, чем:

if response.nil?
  # do something else
else
  # do something ('happy path')
end

if (object)Картина очень часто встречается в Ruby - кода. Это также приводит к рефакторингу, например:

if response = responses.to_a.first
  do_something_with(response)
else
  # response is equal to nil
end

Помните также, что метод Ruby возвращается nilпо умолчанию. Так:

def initial_response
  if @condition
    @responses.to_a.first
  else
    nil
  end
end

можно упростить до:

def initial_response
  if @condition
    @responses.to_a.first
  end
end

Таким образом, мы можем продолжить рефакторинг:

if response = initial_response
  do_something_with(response)
else
  # response is equal to nil
end

Теперь вы можете утверждать, что возвращение nil- это не всегда лучшая идея, так как это означает, что нужно искать nilвезде. Но это еще один чайник рыбы. Учитывая, что тестирование на предмет «наличие или отсутствие» является таким частым требованием, достоверность объектов является полезным аспектом Ruby, хотя и удивительным для новичков в языке.

изыскание
источник
2

Он не только if variable.nil?больше похож на естественный язык, но и защищает программиста от случайного присвоения ему falseзначения и попадания в ваше ifутверждение, поскольку Ruby является свободно типизированным языком.

Грег Бургардт
источник
1
Таким образом, первоначальный комментарий в исходном вопросе был неверным? Должно было быть "делать вещи, когда переменная ноль или ложь"? И поскольку код, не соответствующий комментарию, является ошибкой, есть ли ошибка сразу?
gnasher729
Верный. Простой тест на правдивость может привести к логическим ошибкам.
Грег Бургхардт
0

Идиоматически, unless variableпредпочтительнее if !variable. Отрицательные ifоператоры часто считаются запахом кода, так как при скимминге легче пропустить отрицание.

Более общая картина здесь заключается в том, что выполнение nilтаких проверок также является запахом кода. Для правильного OO стремитесь использовать шаблон нулевого объекта, чтобы такая проверка никогда не требовалась. http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/

Скажите объектам, что делать, не спрашивайте их, кто они. Это иногда известно как сказать не спрашивай

Мэтт Гибсон
источник