next versus if in a .each loop?
I have a text processing thing I'm doing in Ruby. Basically, I have to implement a simple state machine (with one character look-behind).
My code at the moment looks like this:
text.each{ |c|
...
...
...
...
if @state!=:some_state
next
end
#processing stuff for if in :some_state mode
...
...
...
...
...
}
Is this开发者_JAVA技巧 proper? Or should it rather be implemented like:
text.each{ |c|
...
...
...
...
if @state==:some_state
#processing stuff for if in :some_state mode
...
...
...
...
...
end
}
Is there a right way or is it just preference? Which one blends more with "the ruby way" of doing things?
Totally agree with @DigitalRoss and I have seen people using next
if there is complicated piece of code after some condition is being evaluated i.e.
next if @state!=:some_state
# some long complicated code
on the other hand if there is a simple operation that needs to be performed on the basis of some condition then I would prefer
if @state == :some_state
#call_a_method_to_do_something
end
OR
call_a_method if @state == :some_state
Having said that, its bad practice to write long complicated code. If your code is clean and well designed then you would never have to use next
within your code.
I think that the example you gave doesn't really capture situation where doing next
makes a difference. Consider the situation where you have multiple "next-points" in your code:
text.each do |c|
next if @state == :state1
...
next if @state == :state2
...
next if @state == :state3
...
end
and compare it with if-variant:
text.each do |c|
unless @state == :state1
...
unless @state == :state2
...
unless @state == :state3
...
end
end
end
end
Although the first could be viewed as spaghetti-style by some purists, IMHO it is more readable than the latter.
Do it the second way
Some schools of thought are opposed to things in various languages like next
, retry
, continue
, and break
, because they are just a little bit too much in the direction of the disrespected goto
statement.
Those statements do have their use cases, but in general it's a bad idea to deliberately "spaghettify" the code when a structured downward-pointing construct will accomplish the same thing. Now if the condition called for skipping the entire loop body, in that case I might prefer the use of next
.
i would go for:
text.each{ |c|
...
... Generic state processing
...
case @state
when :state_1 then code
when :state_2 then code
end
}
But if it's as on the first sample ( meaning just 1 state needs extra processing )
text.each{ |c|
...
... Generic state processing
...
next unless @state == :state_1
...
... Code that process states other than :state_1
}
Going even further instead of hitting the instance variable, it sound nicer to ask the object if it's in the state we need like:
def processed?
@state == :state_1
end
...
next unless processed? # sounds like natural language...
...
Reasoning a little bit further, I think one liners like 'next unless processed?' are good only when there are no more than 10 lines of code in the same indentation level, otherwise i rather do the other, so indentation will help me understand at first glance what's happening
精彩评论