0Pricing
Scala for Backend Engineering & Functional Programming · Lección

Clausuras

Capture el estado

Clausuras es una lección gratuita de Scala for Backend Engineering & Functional Programming en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Scala for Backend Engineering & Functional Programming, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.

¿Qué es un cierre?

Un cierre es una función que captura variables del ámbito circundante donde se definió. La función «cierra sobre» esas variables y conserva el acceso a ellas incluso después de que ese ámbito haya terminado.

object Main {
  def main(args: Array[String]): Unit = {
    val factor = 3
    val multiply = (x: Int) => x * factor
    println(multiply(5))
  }
}

Capturar una variable libre

En x => x * factor, x es un parámetro, pero factor es una variable libre tomada del ámbito envolvente. La función conserva una referencia a ella.

object Main {
  def main(args: Array[String]): Unit = {
    val greeting = "Hello"
    val greet = (name: String) => s"$greeting, $name!"
    println(greet("Ann"))
    println(greet("Bob"))
  }
}

Los cierres sobreviven a su ámbito

Cuando una función devuelve un cierre, las variables capturadas permanecen activas mientras exista el cierre, aunque la función que lo definió ya haya terminado.

object Main {
  def makeAdder(n: Int): Int => Int = x => x + n
  def main(args: Array[String]): Unit = {
    val add10 = makeAdder(10)
    val add100 = makeAdder(100)
    println(add10(5))
    println(add100(5))
  }
}

Cada cierre tiene su propia captura

Llamar dos veces a una fábrica de funciones produce dos cierres independientes, cada uno de los cuales recuerda su propio valor capturado.

object Main {
  def prefixer(p: String): String => String = s => p + s
  def main(args: Array[String]): Unit = {
    val withDr = prefixer("Dr. ")
    val withMr = prefixer("Mr. ")
    println(withDr("Smith"))
    println(withMr("Jones"))
  }
}

Capturar estado mutable

Un cierre puede capturar un var y leerlo y actualizarlo. Esto permite que mantenga su estado entre llamadas, como un contador.

object Main {
  def main(args: Array[String]): Unit = {
    var count = 0
    val increment = () => { count += 1; count }
    println(increment())
    println(increment())
    println(increment())
  }
}

Una fábrica de contadores

Combine las ideas: una función que devuelve un cierre que captura su propio var privado le proporciona un contador encapsulado e independiente.

object Main {
  def counter(): () => Int = {
    var n = 0
    () => { n += 1; n }
  }
  def main(args: Array[String]): Unit = {
    val c1 = counter()
    val c2 = counter()
    println(c1())
    println(c1())
    println(c2())
  }
}

Los cierres capturan referencias, no copias

Un cierre captura la variable, no una instantánea. Si el var capturado cambia después de crear el cierre, este verá el nuevo valor.

object Main {
  def main(args: Array[String]): Unit = {
    var msg = "first"
    val show = () => println(msg)
    show()
    msg = "second"
    show()
  }
}

Prefiera capturar val

Capturar un val inmutable evita sorpresas: el valor capturado nunca cambia, por lo que el cierre se comporta de forma predecible. En código funcional, prefiera capturar val.

object Main {
  def main(args: Array[String]): Unit = {
    val taxRate = 0.2
    val withTax = (price: Double) => price * (1 + taxRate)
    println(withTax(100))
  }
}

Cierres con métodos de colecciones

Las lambdas que se pasan a map, filter, etc. son cierres cuando hacen referencia a variables externas. Esto es extremadamente habitual en Scala.

object Main {
  def main(args: Array[String]): Unit = {
    val threshold = 3
    val nums = List(1, 2, 3, 4, 5)
    val big = nums.filter(_ > threshold)
    println(big)
  }
}

Un problema al capturar variables en bucles

En Scala, la variable de un bucle for es un enlace nuevo en cada iteración, por lo que los cierres capturan valores distintos. Esto evita un error clásico que aparece en algunos otros lenguajes.

object Main {
  def main(args: Array[String]): Unit = {
    val fns = for (i <- 1 to 3) yield () => i
    println(fns.map(f => f()))
  }
}

Los cierres encapsulan comportamiento y datos

Un cierre agrupa comportamiento (el cuerpo de la función) y datos (las variables capturadas). Es una alternativa ligera a un objeto pequeño con un método.

object Main {
  def discounter(rate: Double): Double => Double = price => price * (1 - rate)
  def main(args: Array[String]): Unit = {
    val sale = discounter(0.25)
    println(sale(80))
    println(sale(200))
  }
}

Comprobación rápida

¿Qué captura un cierre de su ámbito circundante?

Repaso

Ha aprendido sobre los cierres:

  • Un cierre captura las variables libres de su ámbito envolvente
  • Las variables capturadas sobreviven a la función que las define
  • Cada instancia de un cierre tiene su propio estado capturado
  • Los cierres capturan referencias, por lo que las capturas mutables pueden cambiar
  • Las lambdas de map/filter son cierres habituales

Preguntas frecuentes

¿La lección «Clausuras» es gratis?

Sí — el texto completo de «Clausuras» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Scala for Backend Engineering & Functional Programming, actualiza a CoddyKit PRO. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.

¿Qué aprenderé en «Clausuras»?

Capture el estado Practicas Scala for Backend Engineering & Functional Programming con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Scala for Backend Engineering & Functional Programming?

No se requiere experiencia previa. Scala for Backend Engineering & Functional Programming en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Clausuras»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Scala for Backend Engineering & Functional Programming?

Sí. Cada lección de Scala for Backend Engineering & Functional Programming incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Funciones como valores
  2. Currificación
  3. Composición
  4. Clausuras
← Volver a Scala for Backend Engineering & Functional Programming