следующий или если в цикле .each? - PullRequest
25 голосов
/ 17 февраля 2010

У меня есть функция обработки текста, которую я делаю в 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
}

Есть ли правильный путь или это просто предпочтение? Какой из них больше сочетается с "рубиновым" способом ведения дел?

Ответы [ 4 ]

21 голосов
/ 17 февраля 2010

Полностью согласен с @DigitalRoss, и я видел людей, использующих next, если есть сложный фрагмент кода после оценки какого-либо условия, т.е.

 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 в вашем коде.

5 голосов
/ 17 февраля 2010

Я думаю, что приведенный вами пример не отражает ситуацию, когда выполнение 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 голосов
/ 17 февраля 2010

Сделай это вторым способом

Некоторые школы мысли противостоят вещам на разных языках, таких как next, retry, continue и break, потому что они просто слишком много в направлении неуважительного goto заявление.

Эти операторы имеют свои варианты использования, но в целом это плохая идея, чтобы преднамеренно "спагетифицировать" код, когда структурированная нисходящая конструкция будет выполнять то же самое. Теперь, если условие требует пропуска всего тела цикла, в этом случае я мог бы предпочесть использование next.

1 голос
/ 10 сентября 2011

я бы пошел на:

text.each{ |c|
  ...
  ... Generic state processing
  ...
  case @state
    when :state_1 then code
    when :state_2 then code
  end
}

Но если это как в первом примере (то есть только 1 состояние требует дополнительной обработки)

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 строк кода, в противном случае я предпочитаю делать другое, поэтому отступы помогут мне на первый взгляд понять, что происходит

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...