Usare Option e Future
Concatenazione monadica
Usare Option e Future è 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.
Oltre le collection
Le for-comprehension non sono limitate alle liste. È possibile usare qualsiasi tipo che fornisca map e flatMap, inclusi Option, Either, Try e Future. Questa tecnica si chiama concatenamento monadico.
object Main {
def main(args: Array[String]): Unit = {
val sum = for {
a <- Some(10)
b <- Some(20)
} yield a + b
println(sum)
}
}Option interrompe l'elaborazione con None
Con Option, la comprehension produce un risultato solo se ogni generatore è Some. Se uno qualsiasi è None, l'intero risultato è None e i passaggi successivi vengono saltati.
object Main {
def main(args: Array[String]): Unit = {
val ok = for {
a <- Some(2)
b <- Some(3)
} yield a * b
val missing = for {
a <- Some(2)
b <- None: Option[Int]
} yield a * b
println(ok)
println(missing)
}
}Concatenare ricerche opzionali
Un modello comune consiste nel cercare chiavi in una Map, dove ogni ricerca restituisce un Option. La for-comprehension produce un valore solo se tutte le ricerche hanno esito positivo.
object Main {
def main(args: Array[String]): Unit = {
val prices = Map("apple" -> 3, "bread" -> 5)
val total = for {
a <- prices.get("apple")
b <- prices.get("bread")
} yield a + b
println(total)
val missing = for {
a <- prices.get("apple")
c <- prices.get("milk")
} yield a + c
println(missing)
}
}Perché è meglio degli if-else annidati
Senza le for-comprehension dovrebbe annidare i pattern match o i controlli sui valori null. La forma monadica appiattisce quella piramide in una sequenza lineare e pulita.
object Main {
def parse(s: String): Option[Int] = s.toIntOption
def main(args: Array[String]): Unit = {
val result = for {
x <- parse("40")
y <- parse("2")
} yield x + y
println(result)
}
}Le guardie funzionano anche con Option
Una guardia all'interno di una comprehension su Option trasforma un valore in None quando la condizione non è soddisfatta, agendo come una validazione inline.
object Main {
def main(args: Array[String]): Unit = {
def validate(age: Int): Option[Int] =
for {
a <- Some(age)
if a >= 18
} yield a
println(validate(25))
println(validate(15))
}
}Introduzione a Future
Un Future rappresenta un valore che sarà disponibile in seguito. Come Option, dispone di map e flatMap, quindi le for-comprehension possono mettere in sequenza passaggi asincroni.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._
object Main {
def main(args: Array[String]): Unit = {
val f = for {
a <- Future(10)
b <- Future(20)
} yield a + b
println(Await.result(f, 2.seconds))
}
}Qui i Future vengono eseguiti in sequenza
Quando un generatore dipende da un altro all'interno di una for-comprehension, i future vengono eseguiti in sequenza, perché ogni flatMap attende il risultato precedente.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._
object Main {
def main(args: Array[String]): Unit = {
val f = for {
a <- Future(5)
b <- Future(a * 2)
} yield a + b
println(Await.result(f, 2.seconds))
}
}Eseguire i future in parallelo
Per eseguire i future in parallelo, li avvii prima della for-comprehension e poi li combini. Le attività indipendenti si sovrappongono invece di attendere.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._
object Main {
def main(args: Array[String]): Unit = {
val fa = Future(100)
val fb = Future(200)
val combined = for {
a <- fa
b <- fb
} yield a + b
println(Await.result(combined, 2.seconds))
}
}Either per errori più ricchi
Either[E, A] contiene un valore di errore in caso di fallimento. In una for-comprehension, il primo Left interrompe l'elaborazione e viene restituito.
object Main {
def parse(s: String): Either[String, Int] =
s.toIntOption.toRight(s"not a number: $s")
def main(args: Array[String]): Unit = {
val good = for { a <- parse("3"); b <- parse("4") } yield a + b
val bad = for { a <- parse("3"); b <- parse("x") } yield a + b
println(good)
println(bad)
}
}La stessa struttura per molti tipi
Noti che la comprehension ha un aspetto identico sia con Option, Either, Try sia con Future. Cambia solo la semantica del fallimento. Questa uniformità è la forza del concatenamento monadico.
import scala.util.Try
object Main {
def main(args: Array[String]): Unit = {
val result = for {
a <- Try("21".toInt)
b <- Try("2".toInt)
} yield a * b
println(result)
}
}Non è consentito combinare tipi diversi
Tutti i generatori di una comprehension devono appartenere alla stessa monade. Non può combinare direttamente un generatore Option con un generatore Future; prima deve convertire uno dei due, ad esempio con Future.fromTry, oppure racchiudere l'Option.
object Main {
def main(args: Array[String]): Unit = {
// Convert the Option to keep types consistent
val maybe: Option[Int] = Some(7)
val result = for {
a <- maybe
b <- maybe.map(_ + 1)
} yield a + b
println(result)
}
}Verifica rapida
In una for-comprehension su Option, cosa succede se un generatore produce None?
Riepilogo
Ha imparato il concatenamento monadico con le for-comprehension:
- Funziona con qualsiasi tipo che disponga di
mapeflatMap Optioninterrompe l'elaborazione conNoneEithereTryinterrompono l'elaborazione in caso di fallimento, conservando le informazioni sull'erroreFuturemette in sequenza i passaggi asincroni; li avvii in anticipo per ottenere il parallelismo- Tutti i generatori devono condividere lo stesso tipo di monade
Domande Frequenti
La lezione «Usare Option e Future» è gratuita?
Sì — il testo completo di «Usare Option e Future» è 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 «Usare Option e Future»?
Concatenazione monadica 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 «Usare Option e Future»?
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.
Tutte le lezioni di questo corso
- Desugaring di for
- Filtrare con if
- Generatori multipli
- Usare Option e Future