ruby - objetos - ¿Cómo salir de un bloque de rubí?
ruby for bucle (7)
Para romper el bucle o salir del bucle simplemente use regreso next
palabra clave devolver si element.nil? next if element.nil?
Aquí está la Bar#do_things
:
class Bar
def do_things
Foo.some_method(x) do |x|
y = x.do_something
return y_is_bad if y.bad? # how do i tell it to stop and return do_things?
y.do_something_else
end
keep_doing_more_things
end
end
Y aquí está Foo#some_method
:
class Foo
def self.some_method(targets, &block)
targets.each do |target|
begin
r = yield(target)
rescue
failed << target
end
end
end
end
Pensé en usar raise, pero estoy tratando de hacerlo genérico, así que no quiero poner nada específico en Foo
.
Quería simplemente poder salir de un bloque, algo así como un goto hacia adelante, no realmente relacionado con un bucle. De hecho, quiero separarme de un bloque que está en un bucle sin terminar el bucle. Para hacer eso, hice del bloque un bucle de una iteración:
for b in 1..2 do
puts b
begin
puts ''want this to run''
break
puts ''but not this''
end while false
puts ''also want this to run''
end
Espero que esto ayude al próximo googler que aterrice aquí basado en la línea de asunto.
Quizás pueda usar los métodos incorporados para encontrar elementos particulares en un Array, en lugar de targets
de each
y hacer todo a mano. Algunos ejemplos:
class Array
def first_frog
detect {|i| i =~ /frog/ }
end
def last_frog
select {|i| i =~ /frog/ }.last
end
end
p ["dog", "cat", "godzilla", "dogfrog", "woot", "catfrog"].first_frog
# => "dogfrog"
p ["hats", "coats"].first_frog
# => nil
p ["houses", "frogcars", "bottles", "superfrogs"].last_frog
# => "superfrogs"
Un ejemplo sería hacer algo como esto:
class Bar
def do_things
Foo.some_method(x) do |i|
# only valid `targets` here, yay.
end
end
end
class Foo
def self.failed
@failed ||= []
end
def self.some_method(targets, &block)
targets.reject {|t| t.do_something.bad? }.each(&block)
end
end
Si desea que su bloque devuelva un valor útil (por ejemplo, cuando use #map
, #inject
, etc.), next
y break
también aceptan un argumento.
Considera lo siguiente:
def contrived_example(numbers)
numbers.inject(0) do |count, x|
if x % 3 == 0
count + 2
elsif x.odd?
count + 1
else
count
end
end
end
El equivalente utilizando next
:
def contrived_example(numbers)
numbers.inject(0) do |count, x|
next count if x.even?
next (count + 2) if x % 3 == 0
count + 1
end
end
Por supuesto, siempre puede extraer la lógica necesaria en un método y llamarla desde dentro de su bloque:
def contrived_example(numbers)
numbers.inject(0) { |count, x| count + extracted_logic(x) }
end
def extracted_logic(x)
return 0 if x.even?
return 2 if x % 3 == 0
1
end
Utilice la palabra clave next
. Si no desea continuar con el siguiente elemento, use break
.
Cuando se usa next
dentro de un bloque, hace que el bloque salga de inmediato, devolviendo el control al método del iterador, que puede comenzar una nueva iteración invocando el bloque nuevamente:
f.each do |line| # Iterate over the lines in file f
next if line[0,1] == "#" # If this line is a comment, go to the next
puts eval(line)
end
Cuando se usa en un bloque, break
transfiere el control fuera del bloque, fuera del iterador que invocó el bloque, y a la primera expresión que sigue a la invocación del iterador:
f.each do |line| # Iterate over the lines in file f
break if line == "quit/n" # If this break statement is executed...
puts eval(line)
end
puts "Good bye" # ...then control is transferred here
Y por último, el uso del return
en un bloque:
return
siempre hace que el método de encerrar regrese, sin importar cuán profundamente anidado esté dentro de los bloques (excepto en el caso de las lambdas):
def find(array, target)
array.each_with_index do |element,index|
return index if (element == target) # return from find
end
nil # If we didn''t find the element, return nil
end
utilizar la palabra clave break
lugar de return
next
y el break
parecen hacer lo correcto en este ejemplo simplificado!
class Bar
def self.do_things
Foo.some_method(1..10) do |x|
next if x == 2
break if x == 9
print "#{x} "
end
end
end
class Foo
def self.some_method(targets, &block)
targets.each do |target|
begin
r = yield(target)
rescue => x
puts "rescue #{x}"
end
end
end
end
Bar.do_things
salida: 1 3 4 5 6 7 8