0Pricing
Scala for Backend Engineering & Functional Programming · Aula

Tipos união e interseção

Novos recursos de tipos

Tipos união e interseção é uma aula grátis de Scala for Backend Engineering & Functional Programming no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Scala for Backend Engineering & Functional Programming, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.

Novos recursos de tipos

Scala 3 adiciona tipos união (A | B) e tipos interseção (A & B) ao sistema de tipos. Eles permitem descrever valores com mais precisão, sem hierarquias de herança.

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

Noções básicas dos tipos união

Um tipo união A | B representa um valor que é A ou B. Ele corresponde a um OU da teoria dos conjuntos aplicado aos tipos.

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"))

Uniões não precisam de um supertipo comum

Ao contrário de Either no Scala 2, os tipos união não exigem encapsulamento. Quaisquer dois tipos podem formar uma união sem compartilhar uma classe pai.

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))

Uniões para modelar erros

Os tipos união são úteis para resultados de erro leves, sem um tipo wrapper. Combinados com enums ou singletons, eles ficam fáceis de ler.

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))

Noções básicas dos tipos interseção

Um tipo de interseção A & B representa um valor que é tanto A quanto B. Trata-se de um AND da teoria dos conjuntos, frequentemente usado para combinar características.

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))

A interseção é comutativa

A ordem não importa nos tipos de interseção: A & B é o mesmo tipo que B & A. Isso difere dos tipos compostos da Scala 2, A with B, nos quais a ordem afetava a resolução de alguns membros.

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)

Combinando várias características

É possível fazer a interseção de mais de dois tipos. O resultado exige todas as capacidades listadas.

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))

Aliases de tipo para uniões

Tipos de união longos podem receber um nome com um alias type, mantendo as assinaturas legíveis.

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))

Correspondência exaustiva em uniões

O compilador conhece os membros de uma união, portanto pode verificar se a correspondência está completa. Tratar todas as alternativas torna a correspondência total.

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"))

Alargamento de uniões

Ao atribuir um valor de união a uma variável cujo tipo é inferido, a Scala mantém o tipo de união. Tenha em mente que algumas operações alargam o tipo para o menor supertipo comum; por isso, use uma anotação quando quiser preservar a união.

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 usar cada recurso

Escolha a ferramenta certa.

  • União: um valor é um entre vários tipos (OR).
  • Interseção: um valor satisfaz várias características ao mesmo tempo (AND).
  • As uniões evitam tipos contêiner; as interseções evitam hierarquias de herança profundas.
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ção rápida

Teste sua compreensão dos tipos de união e de interseção.

Recapitulação

Você aprendeu os tipos de união e de interseção da Scala 3.

  • A | B: o valor é A ou B, sem necessidade de um contêiner ou de um pai comum.
  • A & B: o valor é A e B ao mesmo tempo; a operação é comutativa.
  • Use correspondência de padrões para restringir uniões; combine características com interseções.
  • Use aliases type para nomear uniões longas.
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)))

Perguntas Frequentes

A aula “Tipos união e interseção” é grátis?

Sim — o texto completo de “Tipos união e interseção” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Scala for Backend Engineering & Functional Programming, atualize para CoddyKit PRO. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.

O que vou aprender em “Tipos união e interseção”?

Novos recursos de tipos Você pratica Scala for Backend Engineering & Functional Programming com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Scala for Backend Engineering & Functional Programming?

Nenhuma experiência prévia é necessária. Scala for Backend Engineering & Functional Programming no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Tipos união e interseção”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Scala for Backend Engineering & Functional Programming?

Sim. Cada aula de Scala for Backend Engineering & Functional Programming inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Indentação significativa
  2. Enums no Scala 3
  3. Tipos opacos
  4. Tipos união e interseção
← Voltar para Scala for Backend Engineering & Functional Programming