Closure
Catturare lo stato
Closure è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.
Che cos'è una closure?
Una closure è una funzione che cattura le variabili dell'ambito circostante in cui è stata definita. La funzione mantiene l'accesso a tali variabili anche dopo che l'ambito ha restituito il controllo.
object Main {
def main(args: Array[String]): Unit = {
val factor = 3
val multiply = (x: Int) => x * factor
println(multiply(5))
}
}Catturare una variabile libera
In x => x * factor, x è un parametro, mentre factor è una variabile libera proveniente dall'ambito che la racchiude. La funzione ne conserva un riferimento.
object Main {
def main(args: Array[String]): Unit = {
val greeting = "Hello"
val greet = (name: String) => s"$greeting, $name!"
println(greet("Ann"))
println(greet("Bob"))
}
}Le closure sopravvivono al proprio ambito
Quando una funzione restituisce una closure, le variabili catturate rimangono vive finché rimane viva la closure, anche se la funzione che la definisce ha già terminato l'esecuzione.
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))
}
}Ogni closure ha la propria cattura
Chiamare due volte una function factory produce due closure indipendenti, ognuna delle quali ricorda il proprio valore catturato.
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"))
}
}Catturare uno stato modificabile
Una closure può catturare un var e leggerlo e aggiornarlo. In questo modo può mantenere uno stato tra una chiamata e l'altra, come un contatore.
object Main {
def main(args: Array[String]): Unit = {
var count = 0
val increment = () => { count += 1; count }
println(increment())
println(increment())
println(increment())
}
}Una factory per contatori
Combini queste idee: una funzione che restituisce una closure con un proprio var privato catturato permette di ottenere un contatore incapsulato e indipendente.
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())
}
}Le closure catturano riferimenti, non copie
Una closure cattura la variabile, non un'istantanea. Se il var catturato cambia dopo la creazione della closure, la closure vede il nuovo valore.
object Main {
def main(args: Array[String]): Unit = {
var msg = "first"
val show = () => println(msg)
show()
msg = "second"
show()
}
}Preferire la cattura di val
Catturare un val immutabile evita sorprese: il valore catturato non cambia mai, quindi la closure si comporta in modo prevedibile. Nel codice funzionale, preferisca la cattura di val.
object Main {
def main(args: Array[String]): Unit = {
val taxRate = 0.2
val withTax = (price: Double) => price * (1 + taxRate)
println(withTax(100))
}
}Le closure con i metodi delle collezioni
Le lambda passate a map, filter e così via sono closure ogni volta che fanno riferimento a variabili esterne. È una situazione estremamente comune in 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 di cattura nei cicli
In Scala, la variabile di un ciclo for è un nuovo binding a ogni iterazione, quindi le closure catturano valori distinti. In questo modo si evita un errore classico presente in alcuni altri linguaggi.
object Main {
def main(args: Array[String]): Unit = {
val fns = for (i <- 1 to 3) yield () => i
println(fns.map(f => f()))
}
}Le closure incapsulano comportamento e dati
Una closure combina il comportamento (il corpo della funzione) con i dati (le variabili catturate). È un'alternativa leggera a un piccolo oggetto con un solo metodo.
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))
}
}Verifica rapida
Che cosa cattura una closure dall'ambito circostante?
Riepilogo
Ha imparato a conoscere le closure:
- Una closure cattura le variabili libere dell'ambito che la racchiude
- Le variabili catturate sopravvivono alla funzione che le definisce
- Ogni istanza di closure ha il proprio stato catturato
- Le closure catturano riferimenti, quindi le catture modificabili possono cambiare
- Le lambda passate a
map/filtersono closure usate quotidianamente
Domande Frequenti
La lezione «Closure» è gratuita?
Sì — il testo completo di «Closure» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.
Cosa imparerò in «Closure»?
Catturare lo stato Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?
Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Closure»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?
Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.