Cómo salir de un bloque de rubíes?
Aquí está 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
.
7 answers
Usa la palabra clave next
. Si no desea continuar con el siguiente elemento, utilice break
.
Cuando next
se usa dentro de un bloque, hace que el bloque salga inmediatamente, devolviendo el control al método iterador, que luego puede comenzar una nueva iteración invocando el bloque de nuevo:
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 control fuera del bloque, fuera del iterador que invocó el bloque, y a la primera expresión después de 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 finalmente, el uso de return
en un bloque:
return
siempre hace que el método de enclosing regrese, independientemente de cuán profundamente anidado esté dentro de los bloques (excepto en el caso de 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-09 21:55:18
Solo quería ser capaz de salir de un bloque, algo así como un goto hacia adelante, no relacionado realmente con un bucle. De hecho, quiero romper de un bloque que está en un bucle sin terminar el bucle. Para hacer eso, hice el 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 siguiente googler que aterrice aquí basado en la línea de asunto.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-12 04:14:13
Si desea que su bloque devuelva un valor útil (por ejemplo, al usar #map
, #inject
, etc.), next
y break
también aceptan un argumento.
Considere 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 usando 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 puedes extraer la lógica necesaria en un método y llamarla desde dentro de tu 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-16 20:51:19
Usa la palabra clave break
en lugar de return
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-10 00:52:30
Tal vez pueda usar los métodos integrados para encontrar elementos particulares en una matriz, en lugar de each
-ing targets
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-03 08:05:45
next
y 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-28 22:02:33
Para romper el bucle o salir del bucle simplemente use return next
palabra clave
devuelve el elemento if.nil? next if element.nil?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-15 01:37:11