Следующий в сравнении с if в цикле .each?
У меня есть текстовая обработка, которую я делаю в Ruby. В принципе, я должен реализовать простой конечный автомат (с одним символом).
Мой код в данный момент выглядит так:
text.each{ |c|
...
...
...
...
if @state!=:some_state
next
end
#processing stuff for if in :some_state mode
...
...
...
...
...
}
Это правильно? Или он должен быть реализован следующим образом:
text.each{ |c|
...
...
...
...
if @state==:some_state
#processing stuff for if in :some_state mode
...
...
...
...
...
end
}
Есть ли правильный путь или это просто предпочтение? Какой из них больше сочетается с "рубиновым способом"? "
Ответы
Ответ 1
Полностью согласен с @DigitalRoss, и я видел людей, использующих next
, если есть сложная часть кода после того, как какое-либо условие оценивается i.e.
next if @state!=:some_state
# some long complicated code
с другой стороны, если есть простая операция, которая должна выполняться на основе некоторого условия, я бы предпочел
if @state == :some_state
#call_a_method_to_do_something
end
OR
call_a_method if @state == :some_state
Сказав это, его плохая практика - написать длинный сложный код. Если ваш код чист и хорошо разработан, вам никогда не придется использовать next
в вашем коде.
Ответ 2
Я думаю, что пример, который вы дали, на самом деле не фиксирует ситуацию, когда выполнение next
имеет значение. Рассмотрим ситуацию, когда в вашем коде несколько "следующих точек":
text.each do |c|
next if @state == :state1
...
next if @state == :state2
...
next if @state == :state3
...
end
и сравните его с if-вариантом:
text.each do |c|
unless @state == :state1
...
unless @state == :state2
...
unless @state == :state3
...
end
end
end
end
Хотя первый может быть рассмотрен некоторыми пуристами в стиле спагетти, ИМХО он более читабельен, чем последний.
Ответ 3
Сделайте это вторым способом
Некоторые школы мысли выступают против вещей на разных языках, таких как next
, retry
, continue
и break
, потому что они немного слишком сильно направлены в сторону неутешительного goto
утверждение.
У этих утверждений есть свои варианты использования, но в целом это плохая идея сознательно "расстегнуть" код, когда структурированная конструкция, направленная вниз, выполнит одно и то же. Теперь, если условие вызвало пропущение всего тела цикла, в этом случае я мог бы предпочесть использование next
.
Ответ 4
я хотел бы:
text.each{ |c|
...
... Generic state processing
...
case @state
when :state_1 then code
when :state_2 then code
end
}
Но если это как на первом примере (что означает только одно состояние, требуется дополнительная обработка)
text.each{ |c|
...
... Generic state processing
...
next unless @state == :state_1
...
... Code that process states other than :state_1
}
Идя еще дальше, вместо того, чтобы ударять переменную экземпляра, лучше слышать объект, если он находится в нужном нам состоянии:
def processed?
@state == :state_1
end
...
next unless processed? # sounds like natural language...
...
Рассуждая немного дальше, я думаю, что один лайнер вроде "следующий, если не обработан?" хороши только тогда, когда на одном и том же уровне отступов имеется не более 10 строк кода, иначе я скорее сделаю другой, поэтому отступы помогут мне понять на первый взгляд, что происходит