+54 911 66509220

Blog

Blog
4 Feb 2015

Tutorial de Ruby – Parte 14 – Iteradores

/
Creado por
/
Comentarios0

Capítulo 10. Iteradores

 

Los iteradores no son un concepto original de Ruby. Son comunes en otros lenguajes orientados a objetos. También se utilizan en Lisp aunque no se les conoce como iteradores. Sin embargo este concepto de iterador es muy poco familiar para muchas personas por lo que se explorará con detalle.

 

Como ya se sabe, el verbo iterar significa hacer la misma cosa muchas veces, por lo tanto un iterador es algo que hace la misma cosa muchas veces.

 

Al escribir código se necesitan bucles en diferentes situaciones. En C, se codifican utilizando for o while. Por ejemplo:

 

char *str;

for (str = “abcdefg”; *str != ’\0’; str++) {

/* aquí procesamos los caracteres */

}

 

La sintaxis del for(…) de C nos dota de una abstracción que nos ayuda en la creación de un bucle pero, la comprobación de si *str es la cadena nula requiere que el programador conozca los detalles de la estructura interna de una cadena. Esto hace que C se parezca a un lenguaje de bajo nivel. Los lenguajes de alto nivel se caracterizan por un soporte más flexible a la iteración. Consideremos el siguiente guión de la shell sh:

 

#!/bin/sh

 

for i in *.[ch]; do

# … aquí se haría algo con cada uno de los ficheros

done

 

Se procesarían todos los ficheros fuentes en C y sus cabeceras del directorio actual, el comando de la shell se encargaría de los detalles de coger y sustituir los nombres de los ficheros uno por uno. Pensamos que este es un método de trabajo a nivel superior que C, ¿Verdad?

 

Pero hay más cosas a tener en cuenta: aunque está bien que un lenguaje tenga iteradores para todos los tipos de datos definidos en él, es decepcionante tener que volver a escribir bucles de bajo nivel para los tipos de datos propios. En la POO, los usuarios definen sus propios tipos de datos a partir de otros, por lo tanto, esto puede ser un problema serio.

 

Luego, todos los lenguajes OO incluyen ciertas facilidades de iteración. Algunos lenguajes proporcionan clases especiales con este propósito; Ruby nos permite definir directamente iteradores.

 

El tipo strings de Ruby tiene algunos iteradores útiles:

 

ruby> “abc”.each_byte{|c| printf”{%c}”, c}; print “\n”

{a}{b}{c}

nil

 

each_byte es un iterador sobre los caracteres de una cadena. Cada carácter se sustituye en la variable local c. Esto se puede traducir en algo más parecido a C …

 

ruby> s=”abc”;i = 0

0

ruby> while i < s.length

ruby| printf “{%c}”,s[i]; i+=1

ruby| end; print “\n”

{a}{b}{c}

nil

 

… sin embargo el iterador each_byte es a la vez conceptualmente más simple y tiene más probabilidades de seguir funcionando correctamente incluso cuando, hipotéticamente, la clase string se modifique radicalmente en un futuro. Uno de los beneficios de los iteradores es que tienden a ser robustos frente a tales cambios, además, ésta es una característica del buen código en general. (Si, tengamos paciencia también hablaremos de lo que son las clases)

 

each_line es otro iterador de String.

ruby> “a\nb\nc\n”.each_line{|l| print l}

a

b

c

“a\nb\nc\n”

 

Las tareas que más esfuerzo llevan en C (encontrar los delimitadores de línea, generar subcadenas, etc.) se evitan fácilmente utilizando iteradores.

 

La sentencia for que aparece en capítulos previos itera como lo hace el iterador each. El iterador each de String funciona de igual forma que each_line, reescribamos ahora el ejemplo anterior con un for:

 

ruby> for l in “a\nb\nc\n”

ruby| print l

ruby| end

a

b

c

“a\nb\nc\n”

 

Se puede utilizar la sentencia de control retry junto con un bucle de iteración y se repetirá la iteración en curso desde el principio.

 

ruby> c = 0

0

ruby> for i in 0..4

ruby| print i

ruby| if i == 2 and c == 0

ruby| c = 1

ruby| print “\n”

ruby| retry

ruby| end

ruby| end; print “\n”

012

01234

nil

 

A veces aparece yield en la definición de un iterador. yield pasa el control al bloque de código que se pasa al iterador (esto se explorará con más detalle es el capítulo sobre los objetos procedimiento). El siguiente ejemplo define el iterador repeat, que repite el bloque de código el número de veces especificado en el argumento.

ruby> def repeat(num)

ruby| while num > 0

ruby| yield

ruby| num -= 1

ruby| end

ruby| end

nil

ruby> repeat(3){ print “foo\n” }

foo

foo

foo

nil

Con retry se puede definir un iterador que funciona igual que while, aunque es demasiado lento para ser práctico.

 

ruby> def WHILE(cond)

ruby| return if not cond

ruby| yield

ruby| retry

ruby| end

nil

ruby> i=0;WHILE(i<3){ print i; i+=1 }

012nil

 

¿Se entiende lo que son los iteradores? Existen algunas restricciones pero se pueden escribir iteradores propios; y de hecho, al definir un nuevo tipo de datos, es conveniente definir iteradores adecuados para él. En este sentido los ejemplos anteriores no son terriblemente útiles. Volveremos a los iteradores cuando se sepa lo que son las clases.

Leave a Reply

Your email address will not be published.

* Copy This Password *

* Type Or Paste Password Here *

24,099 Spam Comments Blocked so far by Spam Free Wordpress

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.