Viernes, 18 Octubre 2013 20:11

Estructuras de control y Funciones

Hola a tod@s, continuamos con los resúmenes del Libro "SCALA for Impatient". Toca el Capitulo 2:  Estructuras de control y funciones. Los próximos capítulos serán más continuos. Saludos :D

Capitulo II - Estructuras de control y Funciones

2.1 Expresiones condicionales

Scala presenta al igual que java y C++ un condicional if/else, como podemos ver en el ejemplo:

Scala> val x = 7
res8: Int =7
Scala> if (x > 0) 1 else -1
res9: Int = 1

Las expresiones en Scala tienen un tipo, como puede observar en el anterior ejemplo es de tipo entero, en el siguiente ejemplo podemos ver que Scala presenta un tipo "Any" , ya que la expresión condicional presenta por un lado el tipo String y por otro un Int.

Scala> if (x > 0) "Número Positivo" else -1
res9: Any = Número Positivo

Una expresión condicional puede presentar o no un else o en su defecto tener paréntesis vacios.

PRECAUCION: Si va a escribir la sentencia if then else en varias líneas el compilador podría no reconocer el caso else. Ejemplo:

Scala> if(x > 0) 1
res10: AnyVal = 1
Scala> else if( x == 0 ) 0 else -1
:1: error: illegal start of definition
else if( x == 0) 0 else -1
^

La forma ideal de realizar el anterior ejemplo es:

Scala> if(x>0) 1 else if(x==0)0 else -1
res11: Int = 1

2.2 Terminación de una sentencia

Scala permite que se pueda o no escribir el punto y coma al final de una sentencia; pero en caso de querer agregar varias sentencias en una sola línea, debe separarlas mediante un punto y coma, ejemplo:

Scala> var r = 3
r: Int = 3
Scala> var n = 2
n: Int = 2
cala>
if(n > 0) { r = r * n; n-=1}
Scala> println(r)
6
Scala> println(n)
1

2.3 Expresiones en bloque y asignaciones

En Scala un bloque {} contiene una secuencia de expresiones y el resultado es además una expresión. El valor del bloque, es el valor de la última expresión.

Esta característica puede ser bien aprovechada si la inicialización de un val toma más de un paso.

Ejemplo:

Scala> val distancia = { val dx = x – x0; val dy = y-y0; sqrt(dx * dx + dy * dy)}
distancia: Double = 3.1622776601683795

En Scala las asignaciones no tienen un valor, o estrictamente hablando, tienen un valor de tipo Unit. Por tanto, no se puede realizar el siguiente tipo de asignaciones:

Scala> x = y = 1
:8: error: reassignment to val
x = y = 1
^

Porque el resultado de y = 1 es un Unit (equivalente a un void de Java) y lo que espera el valor de x es un Int.

2.4 Entrada y Salida

Scala permite obtener y mostrar información usando las siguientes sentencias:

print () - para imprimir

println - para imprimir con salto de línea

readLine – para leer

readInt - para leer enteros específicamente.

printf - para leer como el formato de C

En el siguiente ejemplo puede observar la lectura y escritura de información

Scala> val name= readLine("Your name:")
Your name:name: String = genso
Scala> val age= readInt()
age: Int = 5

2.5 Bucles

El bucle while tiene la misma estructura que se presenta en java y en C++

Scala> var r= 5
r: Int = 5
Scala> var n=3
n: Int = 3
Scala> while(n>0){r = r * n; n-=1}
Scala> println(r)
30
Scala> println(n)
0

En Scala no se tiene el ciclo for, tal como es conocido en otros lenguajes,pero puede utilizar el método de la clase RichInt, que muestra el siguiente constructor:

For(i <- expr)

Donde se aprecia que en el rango que se coloca en el for puede utilizar to ó until, es decir; to nos permite incluir al último valor del rango mientras que until excluye al último valor del rango, como se muestra en el siguiente ejemplo:

Scala> for(i <- 0 to 4) print(" &"+i)
&0 &1 &2 &3 &4
Scala> for(i <- 0 until 4) print(" *"+i)
*0 *1 *2 *3

2.6 For Loops y for Comprehensions – Avanzado

Scala permite iterar varias expresiones separadas por un punto y coma dentro del for

Ejemplo:

Scala> for(i<-1 to 3; j<-1 to 3) print((10 * i * j)+ " ")
10 20 30 20 40 60 30 60 90

 Dentro del for se puede declarar variables que se usarán dentro del bucle, por ejemplo:

Scala> for(i<-1 to 3; aux=4-i; j<-aux to 3) print((10 * i + j)+ " ")
13 22 23 31 32 33

 Recuerde, cuando el cuerpo del for comienza con yield se construyen colecciones para cada iteración, como se muestra en el ejemplo:

Scala> for(m <- "Hello"; i <- 0 to 1) yield (m + i).toChar
res22: String = HIeflmlmop

2.7 Funciones

Scala tiene funciones además de métodos, un método opera en un objeto, pero una función no. C++ también tiene funciones, pero en Java se puede imitar el comportamiento con métodos estáticos.

Para comprender bien la diferencia entre funciones y métodos en Scala puede consultar el artículo Scala Functions vs. Methods

Una función está determinada por un nombre, parámetros y cuerpo, por Ejemplo:

Scala> def fac(n : Int) = {
var r= 1
for(i <- 1 to n)
 fac: (n: Int)Int
r = r * i
r
}
 Scala> def abs(x: Double) = if(x>0) x else -x
abs: (x: Double)Double

La palabra reservada "return" no es necesaria para devolver el valor de la función. Es posible utilizar return como en Java o C++ para salir de una función inmediatamente, pero no es comúnmente realizado en Scala.

Para funciones recursivas es necesario definir el tipo de retorno de la función.

2.8 Argumentos con nombre y argumentos por defecto

En Scala puede definir los argumentos con nombre y además agregarle un valor por defecto como se muestra en el siguiente ejemplo:

Scala> def argumentos(cadena: String, left:String="[", right:String="]")= left+cadena+right
argumentos: (cadena: String, left: String, right: String)String

2.9 Argumentos variables

En Scala puede enviar como parámetro de la función una cantidad de argumentos o parámetros no definidos, que sean del mismo tipo, como se muestra en el ejemplo.

 Scala> def suma(args: Int*)={var res=0;for(arg<-args) res+= arg; res} suma: (args: Int*)Int Scala> val s= suma(1,3,5,7,8) s: Int = 24

 Ojo, en el ejemplo anterior, no es posible enviar una secuencia de números directamente por medio de una función:

Scala> val su= suma(1 to 10) // Error

 Pero se puede solucionar indicándole al compilador que se desea que parámetro sea considerado como una secuencia de argumentos, agregando : _* para convertir a un argumento de secuencias, como se muestra en el ejemplo:

Scala> val su= suma(1 to 10:_*)
su: Int = 55

 Esta técnica también puede ser utilizada en definiciones recursivas.

2.10 Procedimientos

Scala tiene una notación especial para funciones que no retornan un valor. Si el cuerpo de la función está entre llaves sin que se anteceda el símbolo = entonces el tipo que se retorna es Unit. Tal función se llama Procedimiento. Un procedimiento no retorna un valor y solo es llamado para su efecto secundario.

Ejemplo:

def box(s : String){
val border = "-" + s.length + "--\n"
println(border + "|" + s + "|\n" + border)
}

  2.11 Valores Lazy/Perezosos

Cuando un val es declarado como lazy , su inicialización no sucede hasta que es accedido la primera vez.

Lazy val words = Scala.oi.Source.fromFile("/usr/share/dict/words").mkString

Si el programa nunca accede a words , el archivo nunca es abierto. Los valores lazy son utilizados para retardar el costo de inicialización.

Se puede pensar en los valores lazy, como un intermedio entre un val y un def. Comparando se tiene:

val words = Scala.oi.Source.fromFile("/usr/share/dict/words").mkString
// evaluado cuando word es definido
Lazy val words = Scala.oi.Source.fromFile("/usr/share/dict/words").mkString
// evaluado la primera vez que word es usado
def words = Scala.oi.Source.fromFile("/usr/share/dict/words").mkString
// Evaluado cada vez que word es usado

2.12 Excepciones

Una exception en Scala es trabaja de la misma forma que en Java o C++, cuando se lanza una excepción, el proceso actual es abortado y el sistema de ejecución va por un manejador de excepción que puede aceptar un tipo IllegalArgumentException.

Como en Java los objetos que se lanzan necesitan pertenecer a una subclase de java.lang.Throwable , sin embargo a diferencia de Java Scala no realiza un "chekeo" de excepciones, es decir, nunca tiene que declarar como una función o un método que podría lanzar una excepción.

Una expresión throw tiene el tipo especial Nothing el cual es usado dentro de una expresión if/else. Si una de las ramas tiene el tipo Nothing el tipo de la expresión if/else toma el tipo de la otra rama, por ejemplo:

if (x >= 0) {
sqrt(x)
} else throw new IllegalArgumentExpression("x no debe ser negativo")

La primera rama tiene tipo Double, la segunda tiene tipo Nothing. Por lo tanto la expresión if/else tiene tipo Double

La sintaxis para la captura de excepciones esta modelada en base a la sintaxis de pattern matching:

try {
process(new URL("http://horstmann.com/fred-tiny.gif"))
} catch {
case _ : MalformedURLException => println("Bar URL " + url)
case ex: IOException => ex.printStackTrace()
}

Al igual que Java o C++ los tipos generales de las excepciones deben ir después de los específicos. Nótese que se puede usar el símbolo _ para un nombre de variable que no se necesita.

La declaración try/finally permite disponer de un recurso o no, respecto a una excepción que ha ocurrido, por ejemplo:

var in =new URL("http://horstmann.com/fred-tiny.gif").openStream()
try {
process(in)
} finallly {
in.close()
}

La cláusula finally es ejecutada ocurra o no una excepción en la función process

Notar que las cláusulas try/catch y try/finally tienen objetivos complementarios. La declaración try/catch maneja excepciones y la declaración try/finally toma una acción, generalmente una "limpieza", cuando una excepción no es manejada, es posible combinar ambas declaraciones.

try { ... } catch { ...} finallly { ...}
que es lo mismo que
try { try{...} catch { ...} } finallly { ...}

Sin embargo, esta última combinación es raramente usada.

 Artículo elaborado de manera conjunta por: Nataly Nanda Huanca Patzi y Apolinar Linares Flores

Apolinar Linares Flores

Desarrollador en Scala, Java, apto para dar capacitaciones, por lo tanto curioso a fuerza o cuando realmente le interesa aprender algo nuevo.

Email Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.

18593 comments

Leave a comment

Make sure you enter the (*) required information where indicated. HTML code is not allowed.

FaLang translation system by Faboba