tag section script samp bootstrap 3school ruby

section - ¿Para qué se utiliza la captura y el tiro en Ruby?



wbr tag in html5 (3)

Al escribir algoritmos recursivos que actúan en estructuras de datos anidadas usando funciones recursivas, puede usar throw manera similar a como usaría un break o return temprano al escribir algoritmos iterativos que actúan en datos planos usando bucles.

Por ejemplo, supongamos que tiene una lista de enteros positivos y desea (por alguna razón) escribir una función que devuelva verdadero si se cumple alguna de las siguientes condiciones:

  • La suma de todos los elementos en la lista es mayor que 100
  • Algún elemento en la lista si es igual a 5

Digamos también que siempre desea realizar esta comprobación en una única pasada de corto circuito sobre la lista, en lugar de hacer una llamada de reduce para obtener la suma y otra por separado any? llamar para buscar cinco.

Probablemente escribirías un código como este (de hecho, probablemente HAYAS escrito un código como este en algún idioma en algún momento de tu vida):

def test(list) sum = 0 for i in list sum += i if i == 5 || sum > 100 return true end end return false end

En la mayoría de los lenguajes, no existe un equivalente limpio para romper un algoritmo recursivo que usa una función recursiva. ¡En Ruby, sin embargo, hay! Supongamos que, en lugar de tener una lista y querer verificar si sus elementos contienen un cinco o una suma de más de 100, usted tiene un árbol y quiere verificar si sus hojas contienen un cinco o una suma de más de 100, mientras se cortocircuita y regresa tan pronto como sepa la respuesta.

Puedes hacerlo elegantemente con throw / catch , así:

def _test_recurse(sum_so_far, node) if node.is_a? InternalNode for child_node in node.children sum_so_far = _test_recurse(sum_so_far, child_node) end return sum_so_far else # node.is_a? Leaf sum_so_far += node.value if node.value == 5 throw :passes_test elsif sum_so_far > 100 throw :passes_test else return sum_so_far end end end def test(tree) catch (:passes_test) do _test_recurse(0, tree) return false end return true end

La throw :passes_test aquí actúa un poco como un break ; le permite saltar de toda su pila de llamadas por debajo de la llamada de _test más _test . En otros idiomas, puede hacer esto abusando de las excepciones para este propósito o usando algún código de retorno para decirle a la función recursiva que deje de recurrir, pero esto es más directo y simple.

En la mayoría de los otros idiomas, las declaraciones de captura y lanzamiento hacen lo que hacen las declaraciones de inicio, rescate y elevación en Ruby. Sé que puedes hacer esto con estas dos afirmaciones:

catch :done do puts "I''m done." end

y

if some_condition throw :done end

¿Pero para qué sirve esto? ¿Alguien puede por favor darme un ejemplo de para qué se usan las declaraciones catch and throw en Ruby?


He estado buscando un buen ejemplo por un tiempo, hasta que conocí a Sinatra. En mi humilde opinión, Sinatra expone un ejemplo de uso muy interesante para la catch .

En Sinatra, puede cancelar inmediatamente una solicitud en cualquier momento mediante la halt .

halt

También puede especificar el estado cuando se detiene ...

halt 410

O el cuerpo ...

halt ''this will be the body''

O ambos...

halt 401, ''go away!''

El método de parada se implementa utilizando el tiro .

def halt(*response) response = response.first if response.length == 1 throw :halt, response end

y atrapado por el método de invoke .

Hay varios usos de :halt en Sinatra. Puedes leer el código fuente para más ejemplos.


Puede usar esto para salir de los bucles anidados.

INFINITY = 1.0 / 0.0 catch (:done) do 1.upto(INFINITY) do |i| 1.upto(INFINITY) do |j| if some_condition throw :done end end end end

Si hubiera utilizado una declaración de ruptura anterior, se habría salido del bucle interno. Pero si quieres salir del ciclo anidado, entonces este catch / throw sería realmente útil. Lo he usado here para resolver uno de los problemas de Euler.