Scala for Backend Engineering & Functional Programming · Lezione

Tipi unione e intersezione

Nuove funzionalità dei tipi

Lezione 4 di 413 passaggi

Tipi unione e intersezione è 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.

Nuove funzionalità dei tipi

Scala 3 aggiunge al sistema dei tipi i tipi unione (A | B) e i tipi intersezione (A & B). Consentono di descrivere i valori con maggiore precisione senza gerarchie di ereditarietà.

object Main:
  def main(args: Array[String]): Unit =
    println("Union: A | B, Intersection: A & B")

Nozioni di base sui tipi unione

Un tipo unione A | B rappresenta un valore che è un A oppure un B. È un OR insiemistico tra tipi.

object Main:
  def show(x: Int | String): String = x match
    case i: Int    => s"int $i"
    case s: String => s"str $s"

  def main(args: Array[String]): Unit =
    println(show(42))
    println(show("hi"))

Le unioni non richiedono un supertipo comune

A differenza di Either in Scala 2, i tipi unione non richiedono un wrapper. È possibile unire due tipi qualsiasi senza che condividano una classe genitore.

object Main:
  def parse(input: Int | Boolean): String =
    input match
      case n: Int     => s"number $n"
      case b: Boolean => s"flag $b"

  def main(args: Array[String]): Unit =
    println(parse(7))
    println(parse(true))

Tipi unione per modellare gli errori

I tipi unione sono utili per rappresentare in modo leggero i risultati con errori, senza un tipo wrapper. Combinati con enum o singleton, rendono il codice chiaro.

case object NotFound

object Main:
  def lookup(id: Int): String | NotFound.type =
    if id == 1 then "Alice" else NotFound

  def main(args: Array[String]): Unit =
    println(lookup(1))
    println(lookup(2))

Nozioni di base sui tipi intersezione

Un tipo intersezione A & B rappresenta un valore che è sia A sia B. È un AND insiemistico, spesso usato per combinare trait.

trait Named:
  def name: String
trait Aged:
  def age: Int

object Main:
  def describe(p: Named & Aged): String =
    s"${p.name} is ${p.age}"

  def main(args: Array[String]): Unit =
    val person = new Named with Aged:
      def name = "Bob"
      def age = 40
    println(describe(person))

L'intersezione è commutativa

L'ordine non conta per i tipi intersezione: A & B è lo stesso tipo di B & A. Questo differisce dai tipi composti di Scala 2, A with B, che in alcune risoluzioni dei membri dipendevano dall'ordine.

trait Readable:
  def read: String
trait Writable:
  def write(s: String): Unit

object Main:
  def use(r: Readable & Writable): Unit =
    r.write("x")
    println(r.read)

  def main(args: Array[String]): Unit =
    val rw = new Readable with Writable:
      def read = "data"
      def write(s: String) = println(s"wrote $s")
    use(rw)

Combinare più trait

È possibile intersecare più di due tipi. Il risultato richiede tutte le capacità elencate.

trait A: def a: Int
trait B: def b: Int
trait C: def c: Int

object Main:
  def sum(x: A & B & C): Int = x.a + x.b + x.c

  def main(args: Array[String]): Unit =
    val v = new A with B with C:
      def a = 1
      def b = 2
      def c = 3
    println(sum(v))

Alias di tipo per le unioni

I tipi unione lunghi possono essere denominati con un alias type per mantenere leggibili le firme.

type Json = Int | String | Boolean

object Main:
  def render(j: Json): String = j match
    case i: Int     => i.toString
    case s: String  => s"\"$s\""
    case b: Boolean => b.toString

  def main(args: Array[String]): Unit =
    println(render("hi"))
    println(render(true))

Pattern matching esaustivo sulle unioni

Il compilatore conosce i membri di un'unione, quindi può verificare che il pattern matching sia completo. Gestire ogni alternativa rende il match totale.

type Shape = "circle" | "square"

object Main:
  def sides(s: Shape): Int = s match
    case "circle" => 0
    case "square" => 4

  def main(args: Array[String]): Unit =
    println(sides("square"))

Generalizzazione delle unioni

Quando assegna un valore unione a una variabile il cui tipo viene inferito, Scala conserva il tipo unione. Tenga presente che alcune operazioni effettuano una generalizzazione al minimo maggiorante comune; usi un'annotazione quando desidera preservare l'unione.

object Main:
  def pick(flag: Boolean): Int | String =
    if flag then 1 else "one"

  def main(args: Array[String]): Unit =
    val x: Int | String = pick(false)
    println(x)

Quando usare ciascun tipo

Scelga lo strumento adatto.

  • Unione: un valore è di uno tra diversi tipi (OR).
  • Intersezione: un valore soddisfa contemporaneamente diversi trait (AND).
  • Le unioni evitano i tipi wrapper; le intersezioni evitano gerarchie di ereditarietà profonde.
trait Logger: def log(s: String): Unit
trait Clock:  def now: Long

object Main:
  def run(env: Logger & Clock): Unit =
    env.log(s"time=${env.now}")

  def main(args: Array[String]): Unit =
    val env = new Logger with Clock:
      def log(s: String) = println(s)
      def now = 100L
    run(env)

Verifica rapida

Verifichi la sua comprensione dei tipi unione e intersezione.

Riepilogo

Ha imparato a usare i tipi unione e intersezione di Scala 3.

  • A | B: il valore è A oppure B, senza bisogno di un wrapper o di un genitore comune.
  • A & B: il valore è sia A sia B; è commutativo.
  • Usi il pattern matching per restringere le unioni; combini i trait con le intersezioni.
  • Usi gli alias type per denominare le unioni lunghe.
object Main:
  def length(x: String | List[Int]): Int = x match
    case s: String    => s.length
    case l: List[Int] => l.length

  def main(args: Array[String]): Unit =
    println(length("hello"))
    println(length(List(1, 2, 3)))
Gratis per iniziare

Impara Scala con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
39
Lezioni
143

Domande Frequenti

La lezione «Tipi unione e intersezione» è gratuita?

Sì — il testo completo di «Tipi unione e intersezione» è 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 «Tipi unione e intersezione»?

Nuove funzionalità dei tipi 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 «Tipi unione e intersezione»?

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. Indentazione significativa
  2. Enum in Scala 3
  3. Tipi opachi
  4. Tipi unione e intersezione
← Torna a Scala for Backend Engineering & Functional Programming