until - if unless ruby
Cómo romper el ciclo exterior en Ruby? (8)
Considera throw/catch . Normalmente, el ciclo externo del código siguiente se ejecutará cinco veces, pero con throw puedes cambiarlo a lo que quieras, rompiéndolo en el proceso. Considera este código ruby perfectamente válido:
catch (:done) do
5.times { |i|
5.times { |j|
puts "#{i} #{j}"
throw :done if i + j > 5
}
}
end
En Perl, existe la capacidad de romper un ciclo externo como este:
AAA: for my $stuff (@otherstuff) {
for my $foo (@bar) {
last AAA if (somethingbad());
}
}
(la sintaxis puede ser incorrecta), que utiliza una etiqueta de bucle para romper el bucle externo desde el interior del bucle. ¿Hay algo similar en Ruby?
Envolver un método interno alrededor de los bucles podría hacer el truco Ejemplo:
test = [1,2,3]
test.each do |num|
def internalHelper
for i in 0..3
for j in 0..3
puts "this should happen only 3 times"
if true
return
end
end
end
end
internalHelper
end
Aquí puede hacer una comprobación dentro de cualquiera de los bucles for y regresar desde el método interno una vez que se cumple una condición.
Lo que desea es flujo de control no local, que Ruby tiene varias opciones para hacer:
- Continuaciones,
- Excepciones, y
-
throw
/catch
Continuaciones
Pros:
- Las continuas son el mecanismo estándar para el flujo de control no local. De hecho, puedes construir cualquier flujo de control no local (subrutinas, procedimientos, funciones, métodos, corutinas, máquinas de estado, generadores, condiciones, excepciones) encima de ellos: son más o menos el gemelo más agradable de
GOTO
.
Contras:
- Las continuas no son una parte obligatoria de Ruby Language Specification, lo que significa que algunas implementaciones (XRuby, JRuby, Ruby.NET, IronRuby) no las implementan. Entonces, no puedes confiar en ellos.
Excepciones
Pros:
- Hay un documento que demuestra matemáticamente que las Excepciones pueden ser más poderosas que las Continuaciones. IOW: pueden hacer todo lo que las continuaciones pueden hacer, y más, para que pueda usarlos como reemplazo de las continuaciones.
- Las excepciones están disponibles universalmente.
Contras:
- Se llaman "excepciones", lo que hace que las personas piensen que son "solo por circunstancias excepcionales". Esto significa tres cosas: alguien que lea su código podría no entenderlo, la implementación podría no estar optimizada para eso (y, sí, las excepciones son tontas, lentas en casi cualquier implementación de Ruby) y lo peor de todo es que se cansará de todas esas personas constantemente, balbuceando sin pensar "las excepciones son solo para circunstancias excepcionales", tan pronto como echen un vistazo a su código. (Por supuesto, ni siquiera tratarán de entender lo que estás haciendo).
throw
/ catch
Esto es (más o menos) lo que se vería:
catch :aaa do
stuff.each do |otherstuff|
foo.each do |bar|
throw :aaa if somethingbad
end
end
end
Pros:
- Lo mismo que las excepciones.
- En Ruby 1.9, ¡el uso de excepciones para control-flow es en realidad parte de la especificación del lenguaje ! Bucles, enumeradores, iteradores y todos usan una excepción
StopIteration
para la terminación.
Contras:
- La comunidad de Ruby los odia incluso más que el uso de excepciones para control-flujo.
No, no hay.
Tus opciones son:
- poner el lazo en un método y usar retorno para romper desde el bucle externo
- establecer o devolver una bandera desde el bucle interno y luego verificar esa bandera en el bucle externo y romperla cuando se establece la bandera (lo cual es algo engorroso)
- usa throw / catch para salir del lazo
Puede considerar agregar un indicador, que se establece dentro del bucle interno, para controlar el bucle externo.
''siguiente'' el bucle externo
for i in (1 .. 5)
next_outer_loop = false
for j in (1 .. 5)
if j > i
next_outer_loop = true if j % 2 == 0
break
end
puts "i: #{i}, j: #{j}"
end
print "i: #{i} "
if next_outer_loop
puts "with ''next''"
next
end
puts "withOUT ''next''"
end
''romper'' el bucle externo
for i in (1 .. 5)
break_outer_loop = false
for j in (1 .. 5)
if j > i
break_outer_loop = true if i > 3
break
end
puts "i: #{i}, j: #{j}"
end
break if break_outer_loop
puts "i: #{i}"
end
Quizás esto es lo que quieres? (no probado)
stuff.find do |otherstuff|
foo.find do
somethingbad() && AAA
end
end
El método de búsqueda sigue dando vueltas hasta que el bloque devuelve un valor no nulo o se golpea el final de la lista.
Sé que me arrepentiré de esto en la mañana, pero el simple hecho de usar un ciclo while podría hacer el truco.
x=0
until x==10
x+=1
y=0
until y==10
y+=1
if y==5 && x==3
x,y=10,10
end
end
break if x==10
puts x
end
El if y==5 && x==3
es solo un ejemplo de una expresión que se convierte en verdadera.
while c1
while c2
do_break=true
end
next if do_break
end
o "romper si do_break" dependiendo de lo que quieras