Fundamentos y Sintaxis Básica de Scala
Scala es un lenguaje de programación multiparadigma que integra los enfoques orientado a objetos y funcional. Funciona sobre la Máquina Virtual de Java (JVM), lo que permite interoperar con bibliotecas Java existentes. Su sintaxis es concisa y expresiva, facilitando la resolución de problemas complejos en áreas como concurrencia y procesamiento de datos a gran escala.
Tipos de Datos y Estructuras de Control
Scala proporciona tipos primitivos como Int, Double, Char, Boolean y String. Las estructuras de control incluyan condicionales (if-else) y bucles (while, for), además de construcciones avanzadas como las comprensiones for, que simplifican la iteración y el filtrado de colecciones.
// Ejemplo de comprensión for con filtrado
for (num <- 1 to 10 if num % 2 != 0) println(num)
Programación Orientada a Objetos: Clases, Objetos y Coincidencia de Patrones
Definición de Clases y Objetos
Las clases en Scala actúan como plantillas para objetos, definiendo estado y comportamiento. El soporte para constructores primarios y auxiliares permite una inicialización flexible.
class Empleado(val nombre: String, var salario: Double) {
def describir() = s"$nombre con salario $salario"
}
class Vehiculo(val modelo: String) {
var kilometraje = 0
def this(modelo: String, kilometraje: Int) {
this(modelo)
this.kilometraje = kilometraje
}
}
Los objetos en Scala implementan el patrón singleton, proporcionando puntos de acceso globales o servicios únicos.
<object>
object ConfiguracionGlobal {
def inicializar(): Unit = {
// Lógica de inicialización
}
}
</object>
Coincidencia de Patrones Avanzada
La coincidencia de patrones en Scala va más allá de un simple switch, permitiendo coincidir valores, tipos y estructuras de datos.
entrada match {
case x: String if x.length > 5 => println("Cadena larga")
case x: Int => println("Entero: " + x)
case _ => println("Otro tipo")
}
Técnicas avanzadas incluyen patrones de secuencia y guardas para coincidencias condicionales.
def analizarLista(lista: List[Int]): String = lista match {
case List(a, b, _) if a == b => "Dos primeros iguales"
case cabeza :: cola => "Cabeza: " + cabeza
case Nil => "Lista vacía"
case _ => "Caso genérico"
}
Características Orientadas a Objetos
Los traits en Scala permiten la composición de comportamientos, similar a interfaces pero con implementaciones parciales.
trait Registrable {
def registrar(): Unit
}
class Sistema extends Registrable {
override def registrar(): Unit = println("Sistema registrado")
}
Las clases abstractas definen métodos que deben ser implementados por subclases concretas.
abstract class Figura {
def area(): Double
}
class Circulo(radio: Double) extends Figura {
override def area(): Double = Math.PI * radio * radio
}
Conceptos de Programación Funcional: Funciones de Orden Superior, Clausuars y Currying
Funciones de Orden Superior
Las funciones de orden superior aceptan funciones como argumentos o devuelven funciones como resultados, facilitando abstracciones genéricas.
val numeros = List(1, 2, 3, 4, 5)
val cuadrados = numeros.map(x => x * x)
val pares = numeros.filter(x => x % 2 == 0)
val sumaTotal = numeros.reduce((acum, elem) => acum + elem)
Clausuras y Alcance Funcional
Una clausura es una función que captura variables de su entorno léxico, manteniendo el estado incluso fuera de su alcance original.
def crearMultiplicador(factor: Int) = (numero: Int) => factor * numero
val multiplicadorPor3 = crearMultiplicador(3)
val resultado = multiplicadorPor3(4) // Devuelve 12
Currying y Aplicación Parcial
El currying transforma una función con múltiples parámetros en una serie de funciones con un solo parámetro, mejorando la modularidad.
def sumarCurry(a: Int)(b: Int) = a + b
val sumarCinco = sumarCurry(5) _
val total = sumarCinco(3) // Devuelve 8
Sistema de Tipos e Inferencia de Tipos en Scala
Introducción al Sistema de Tipos
El sistema de tipos en Scala garantiza seguridad en tiempo de compilación, reduce errores en tiempo de ejecución y permite optimizaciones. La inferencia de tipos elimina la necesidad de declaraciones explícitas cuando el compilador puede deducir los tipos.
Conceptos Avanzados de Tipos
Los parámetros de tipo permiten definir funciones y clases genéricas.
def imprimir[T](item: T): T = item
val numero: Int = imprimir(10)
val texto: String = imprimir("Hola")
Las clases de tipo proporcionan mecanismos para agregar comportamientos a tipos existentes mediante instancias implícitas.
trait Formateable[A] {
def formatear(valor: A): String
}
object Formateable {
implicit object IntFormateable extends Formateable[Int] {
def formatear(valor: Int): String = s"Valor: $valor"
}
}
def mostrar[A](item: A)(implicit fm: Formateable[A]): String = fm.formatear(item)
val salida = mostrar(42) // Usa la instancia implícita
Aplicaciones Prácticas de la Inferencia
La inferencia de tipos simplifica el código sin sacrificar la seguridad. Por ejemplo, al usar métodos de colecciones, el compilador infiere los tipos de retorno automáticamente.
val datos = List("uno", "dos", "tres")
val longitudes = datos.map(_.length) // Se infiere List[Int]
Biblioteca de Colecciones y Operaciones Funcionales
Visión General de Colecciones
La biblioteca de colecciones de Scala ofrece estructuras como List, Vector, Array y Map, diseñadas para la inmutabilidad y el procesamiento funcional de datos.
Procesamiento Funcional de Datos
Las operaciones funcionales como map, filter y fold permiten transformar colecciones sin efectos secundarios.
val cifras = List(1, 2, 3, 4)
val dobles = cifras.map(_ * 2) // List(2, 4, 6, 8)
val suma = cifras.fold(0)(_ + _) // 10
Características Avanzadas de Colecciones
Funciones de orden superior como flatMap y zip facilitan el manejo de datos complejos.
val frases = List("hola mundo", "scala genial")
val caracteres = frases.flatMap(_.toCharArray) // Aplana en caracteres
val parejas = List(1, 2, 3).zip(List("a", "b", "c")) // List((1,a), (2,b), (3,c))
Para optimización, se pueden usar vistas o iteradores para evaluación perezosa, reduciendo el uso de memoria en grandes conjuntos de datos.
val rangoGrande = (1 to 1000000).toList
val primerosImpares = rangoGrande.view.filter(_ % 2 != 0).take(5).toList