25 Stimmen

next gegenüber if in einer .each-Schleife?

Ich habe eine Textverarbeitung Sache, die ich in Ruby tun. Grundsätzlich muss ich einen einfachen Zustandsautomaten implementieren (mit einem Zeichen look-behind).

Mein Code sieht im Moment wie folgt aus:

text.each{ |c|
  ...
  ...
  ...
  ...
  if @state!=:some_state
    next
  end
  #processing stuff for if in :some_state mode
  ...
  ...
  ...
  ...
  ...
}

Ist das richtig? Oder sollte es eher so umgesetzt werden:

text.each{ |c|
  ...
  ...
  ...
  ...
  if @state==:some_state
    #processing stuff for if in :some_state mode
    ...
    ...
    ...
    ...
    ...
  end
}

Gibt es einen richtigen Weg oder ist es nur eine Vorliebe? Welcher Weg passt besser zum "ruby way", Dinge zu tun?

21voto

nas Punkte 3676

Ich stimme @DigitalRoss voll und ganz zu und habe Leute gesehen, die next wenn es ein kompliziertes Stück Code gibt, nachdem eine Bedingung ausgewertet wurde, z. B.

 next if @state!=:some_state
 # some long complicated code

Andererseits, wenn es eine einfache Operation gibt, die auf der Grundlage einer Bedingung durchgeführt werden muss, würde ich es vorziehen

 if @state == :some_state
   #call_a_method_to_do_something
 end

 OR

 call_a_method if @state == :some_state

Abgesehen davon ist es schlechte Praxis, langen, komplizierten Code zu schreiben. Wenn Ihr Code sauber und gut gestaltet ist, müssen Sie nie next innerhalb Ihres Codes.

5voto

Mladen Jablanović Punkte 42360

Ich denke, dass das von Ihnen angeführte Beispiel nicht wirklich die Situation erfasst, in der die next macht einen Unterschied. Betrachten Sie die Situation, in der Sie mehrere "next-points" in Ihrem Code haben:

text.each do |c|
  next if @state == :state1
  ...
  next if @state == :state2
  ...
  next if @state == :state3
  ...
end

und vergleichen Sie es mit if-variant:

text.each do |c|
  unless @state == :state1
    ...
    unless @state == :state2
      ...
      unless @state == :state3
        ...
      end
    end
  end
end

Obwohl der erste von einigen Puristen als Spaghetti-Stil angesehen werden könnte, ist er IMHO besser lesbar als der zweite.

3voto

DigitalRoss Punkte 138823

Machen Sie es auf die zweite Art

Einige Denkschulen sind gegen Dinge in verschiedenen Sprachen wie next , retry , continue et break weil sie einfach ein bisschen zu sehr in Richtung des Missachteten gehen goto Erklärung.

Diese Anweisungen haben durchaus ihre Berechtigung, aber im Allgemeinen ist es keine gute Idee, den Code absichtlich zu "spaghettisieren", wenn ein strukturiertes, nach unten gerichtetes Konstrukt das Gleiche bewirkt. Wenn die Bedingung nun das Überspringen des gesamten Schleifenkörpers erfordert, würde ich in diesem Fall die Verwendung von next .

1voto

kasthor Punkte 146

Ich würde mich dafür entscheiden:

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

Aber wenn es so ist wie im ersten Beispiel (d.h. nur 1 Zustand muss extra verarbeitet werden)

text.each{ |c|
  ...
  ... Generic state processing
  ...
  next unless @state == :state_1
  ...
  ... Code that process states other than :state_1
}

Wenn man noch weiter geht, anstatt auf die Instanzvariable zuzugreifen, klingt es netter, das Objekt zu fragen, ob es sich in dem Zustand befindet, den wir brauchen, wie:

def processed?
  @state == :state_1
end

...
next unless processed? # sounds like natural language...
...

Wenn ich noch ein bisschen weiterdenke, denke ich, dass Einzeiler wie "next unless processed?" nur dann gut sind, wenn es nicht mehr als 10 Codezeilen in derselben Einrückungsebene gibt, ansonsten mache ich lieber das andere, so dass die Einrückung mir hilft, auf den ersten Blick zu verstehen, was passiert

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X