0Pricing
Scala for Backend Engineering & Functional Programming · Lezione

Composizione delle operazioni asincrone

Impari a concatenare e combinare più `Future` utilizzando metodi come `map`, `flatMap` e le comprensioni `for`.

Composizione delle operazioni asincrone è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 2 di 3. 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 3 lezioni in totale.

Perché concatenare le operazioni asincrone?

I Future consentono di eseguire attività senza bloccare il programma principale. Ma cosa succede se il risultato di un'attività è necessario per un'altra, oppure se occorre combinare i risultati di più attività?

È qui che la composizione dei Future si rivela utile. Si imparerà a concatenare e combinare queste operazioni asincrone, rendendo il codice Scala più potente e reattivo.

`map`: trasformare il risultato di un Future

Il metodo map si usa quando si dispone di un Future e si vuole trasformare il suo risultato positivo in un altro valore. La funzione di trasformazione fornita verrà applicata quando il Future sarà completato correttamente.

  • Restituisce sempre un nuovo Future.
  • È ideale per semplici trasformazioni sincrone su un risultato asincrono.

`map` in azione (codice)

In questo caso si ottiene un numero da un Future e lo si raddoppia usando map. La trasformazione avviene solo dopo il completamento del Future iniziale.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val originalFuture: Future[Int] = Future {
      Thread.sleep(100) // Simulate work
      10
    }

    val doubledFuture: Future[Int] = originalFuture.map(value => value * 2)

    val result = Await.result(doubledFuture, 1.second)
    println(s"Doubled value: $result")
  }
}

`flatMap`: concatenare i Future

A volte il risultato positivo di un Future deve avviare un altro Future. È qui che flatMap dà il meglio di sé. "Appiattisce" un Future di un Future (Future[Future[T]]) trasformandolo in un singolo Future[T].

  • Usarlo quando la funzione di trasformazione restituisce un Future.
  • È essenziale per le operazioni asincrone sequenziali.

`flatMap` in azione (codice)

Si recupera un ID utente, quindi si usa quell'ID per recuperare i dettagli dell'utente. Ogni passaggio è un'operazione asincrona che restituisce un Future. flatMap garantisce che vengano eseguiti in sequenza.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    def fetchUserId(): Future[Int] = Future {
      Thread.sleep(50)
      123
    }

    def fetchUserDetails(userId: Int): Future[String] = Future {
      Thread.sleep(100)
      s"User $userId details"
    }

    val userDetailsFuture: Future[String] = fetchUserId().flatMap { userId =>
      fetchUserDetails(userId)
    }

    val result = Await.result(userDetailsFuture, 1.second)
    println(s"Details: $result")
  }
}

`map` e `flatMap`: differenza fondamentale

È comune confondere map e flatMap. Occorre ricordare:

  • map: la funzione restituisce un valore normale (ad esempio Int, String). Future[A].map(A => B) produce Future[B].
  • flatMap: la funzione restituisce un altro Future (ad esempio Future[Int], Future[String]). Future[A].flatMap(A => Future[B]) produce Future[B].

flatMap serve per concatenare operazioni asincrone, mentre map serve per trasformare sincronicamente un risultato asincrono.

Comprehension `for`: concatenazione elegante

Le comprehension for di Scala offrono una sintassi chiara e leggibile per concatenare operazioni che coinvolgono map e flatMap. Sono esclusivamente zucchero sintattico, cioè il compilatore le traduce in una serie di chiamate a map, flatMap e filter.

Quando si hanno più operazioni Future dipendenti tra loro, le comprehension for fanno apparire il codice quasi sincrono.

Codice di una comprehension `for`

Questo esempio usa una comprehension for per concatenare la stessa logica di recupero dell'ID utente e dei relativi dettagli già vista con flatMap. Si noti quanto risulti più pulito!

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    def fetchUserId(): Future[Int] = Future {
      Thread.sleep(50)
      123
    }

    def fetchUserName(userId: Int): Future[String] = Future {
      Thread.sleep(100)
      s"Alice (ID: $userId)"
    }

    val userFuture: Future[String] = for {
      id <- fetchUserId()
      name <- fetchUserName(id)
    } yield name

    val result = Await.result(userFuture, 1.second)
    println(s"User name: $result")
  }
}

`zip`: combinare risultati indipendenti

Cosa succede se si hanno due indipendenti Future e si vogliono combinare i relativi risultati quando entrambi sono completati? Il metodo zip è perfetto a questo scopo. Prende un altro Future e restituisce un nuovo Future contenente una coppia (una Tuple) dei rispettivi risultati positivi.

Entrambi i future vengono eseguiti in concorrenza e zip attende che entrambi terminino.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val futureA = Future {
      Thread.sleep(100)
      "Hello"
    }

    val futureB = Future {
      Thread.sleep(50)
      "World"
    }

    val combinedFuture: Future[(String, String)] = futureA.zip(futureB)

    val (greeting, subject) = Await.result(combinedFuture, 1.second)
    println(s"$greeting $subject!")
  }
}

Verifica rapida: composizione dei Future

Si consideri il seguente frammento di codice Scala. Quale sarà l'ultimo valore stampato?

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val f1 = Future { 5 }
    val f2 = f1.map(x => x + 2)
    val f3 = f2.flatMap(y => Future { y * 3 })

    val result = Await.result(f3, 1.second)
    println(result)
  }
}

Riepilogo: concatenare attività asincrone

Sono stati appresi metodi potenti per comporre i Future di Scala:

  • map: trasforma il risultato positivo di un Future in un nuovo valore.
  • flatMap: concatena due Future, usando il risultato del primo per avviare il secondo.
  • comprehension for: offrono una sintassi chiara, simile a quella sincrona, per concatenare flatMap e map.
  • zip: combina i risultati di due Future indipendenti in una tupla.

Questi strumenti sono fondamentali per creare applicazioni asincrone reattive ed efficienti in Scala!

Domande Frequenti

La lezione «Composizione delle operazioni asincrone» è gratuita?

Sì — il testo completo di «Composizione delle operazioni asincrone» è 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 3 lezioni in totale.

Cosa imparerò in «Composizione delle operazioni asincrone»?

Impari a concatenare e combinare più `Future` utilizzando metodi come `map`, `flatMap` e le comprensioni `for`. 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 2 di 3.

Quanto tempo richiede la lezione «Composizione delle operazioni asincrone»?

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

  1. Introduzione a Future e Promise
  2. Composizione delle operazioni asincrone
  3. Gestione degli errori nei Future
← Torna a Scala for Backend Engineering & Functional Programming