Swift: Tutorial de Enums e Correspondência de Padrões do…

Os enums no Swift são muito mais do que "um conjunto de constantes" -- são cidadãos de primeira classe que podem transportar dados, suportar métodos e até se definir recursivamente. São a melhor ferramenta para construir máquinas de estado e tipos de resultado.

1. O Que Você Vai Aprender


2. Uma História Real de uma Desenvolvedora Mobile

(1) Problema: Difícil Expressar os Estados de Resposta da API

Alice encontrou um problema complicado ao construir a camada de rede para um app de notícias. Uma requisição de API poderia retornar múltiplos resultados:

SWIFT
// Inelegant approach: multiple optional variables to represent state
var data: NewsResponse? = nil
var error: Error? = nil
var isLoading = false

Esta abordagem tem três problemas: significado ambíguo quando dados e erro estão ambos presentes, esquecer de tratar um estado causa falhas e lógica espalhada é difícil de manter.

(2) A Solução com Enum de Valores Associados

Use um único enum para unificar todos os estados, com cada caso transportando seus próprios dados:

SWIFT
enum NetworkResult<T> {
    case success(T)
    case failure(Error)
    case loading
}

ResultadoRede<[ArtigoNoticia]> transporta dados de artigo (sucesso), informações de erro (falha) ou o estado de carregamento -- três estados mutuamente exclusivos com semântica clara.

(3) Benefícios: Gerenciamento de Estado do Caos à Clareza

Dimensão Múltiplas Variáveis Optional Enum com Valores Associados
Quantidade de estados 2^N combinações ilegais N estados precisos
Clareza semântica dados/erro podem coexistir Cada estado transporta seus próprios dados
Completude do tratamento Fácil de esquecer casos Verificação de exaustividade do switch
Manutenibilidade do código Espalhado em if-else Centralizado em um tipo

3. Fundamentos de Enum

Enums definem um conjunto de valores relacionados. Os enums do Swift são mais flexíveis que os de outras linguagens -- podem associar métodos, propriedades computadas e subscritos.

(1) Enums Básicos e Valores Brutos

100%
graph LR
    A["enum Bussola {\n case norte\n case sul\n case leste\n case oeste\n}"] --> B["Bussola.norte"]
    A --> C["Bussola.sul"]
    A --> D["Bussola.leste"]
    A --> E["Bussola.oeste"]

Um valor bruto é um valor fixo por trás de cada caso do enum, que pode ser de tipos como String ou Int.

Tipo de Valor Bruto Declaração Valor
Int enum Status: Int { case ok = 200 } Inteiro
String enum Direcao: String { case norte = "N" } String
Int Implícito enum Nota: Int { case a, b, c } Incrementa a partir de 0
String Implícito enum Codigo: String { case vermelho, verde } Igual ao nome do caso

▶ Exemplo: Enum de Código de Status HTTP

SWIFT
// ============================================
// HTTP status code enum using raw values
// ============================================
enum HTTPStatus: Int {
    case ok = 200
    case created = 201
    case badRequest = 400
    case unauthorized = 401
    case notFound = 404
    case serverError = 500
}
let status = HTTPStatus.notFound
print("Code: \(status.rawValue)")
print("Name: \(status)")
// Create from raw value
let parsed = HTTPStatus(rawValue: 200)
print("Parsed: \(parsed ?? .serverError)")

Saída:

TEXT 📖 Somente leitura
Code: 404
Name: notFound
Parsed: ok

(2) Métodos e Propriedades Computadas de Enum

Enums podem definir métodos e propriedades assim como structs.

▶ Exemplo: Enum com Métodos

SWIFT
// ============================================
// Custom enum method: determine status category
// ============================================
enum HTTPStatus: Int {
    case ok = 200
    case created = 201
    case badRequest = 400
    case unauthorized = 401
    case notFound = 404
    case serverError = 500
    var isSuccess: Bool {
        rawValue >= 200 && rawValue < 300
    }
    var description: String {
        switch self {
        case .ok: return "OK"
        case .created: return "Created"
        case .badRequest: return "Bad Request"
        case .unauthorized: return "Unauthorized"
        case .notFound: return "Not Found"
        case .serverError: return "Internal Server Error"
        }
    }
}
let code = HTTPStatus.ok
print("\(code.rawValue) \(code.description) - Success: \(code.isSuccess)")

Saída:

TEXT 📖 Somente leitura
200 OK - Success: true

4. Valores Associados e Correspondência de Padrões

Valores associados são uma característica central que diferencia os enums do Swift de outras linguagens -- cada caso pode transportar dados adicionais de tipos diferentes.

(1) Sintaxe de Valor Associado

100%
graph TB
    A["ResultadoRede<T>"] --> B["sucesso(T) - transporta dados"]
    A --> C["falha(Error) - transporta erro"]
    A --> D["carregando - sem dados"]
    B --> E["switch resultado {\n case .sucesso(let dados):\n   mostrar(dados)\n case .falha(let erro):\n   mostrar(erro)\n case .carregando:\n   mostrarSpinner()\n}"]
Característica Valores Brutos Valores Associados
Tipo de valor Constante fixa Dados variáveis
Momento de armazenamento Determinado na definição Passado na criação
Por caso Todos os casos têm o mesmo tipo de valor Cada caso pode diferir
Caso de uso Mapear códigos fixos Transportar dados dinâmicos

▶ Exemplo: Tratando Resultados de Requisição de Rede

SWIFT
// ============================================
// Associated value enum for handling API responses
// ============================================
enum NetworkResult<T> {
    case success(T)
    case failure(String)
    case loading
}
func handleResponse<T>(_ result: NetworkResult<T>) {
    switch result {
    case .success(let data):
        print("Successfully received data: \(data)")
    case .failure(let error):
        print("Request failed: \(error)")
    case .loading:
        print("Loading...")
    }
}
handleResponse(NetworkResult.success("User Info"))
handleResponse(NetworkResult.failure("Network connection timed out"))
handleResponse(NetworkResult.loading)

Saída:

TEXT 📖 Somente leitura
Successfully received data: User Info
Request failed: Network connection timed out
Loading...

(2) Correspondência de Padrões com if-case e guard-case

Além do switch, você pode usar if case e guard case para correspondência de caso único.

▶ Exemplo: Correspondência Concisa de Caso Único

SWIFT
// ============================================
// Concise usage of if-case and guard-case
// ============================================
enum Measurement {
    case weight(Double)
    case height(Double)
    case count(Int)
}
let record = Measurement.weight(75.5)
// if-case: only care about one case
if case .weight(let kg) = record, kg > 70 {
    print("Weight exceeds 70kg: \(kg)")
}
// guard-case: early exit
func process(_ m: Measurement) {
    guard case .count(let n) = m else {
        print("Not a count type")
        return
    }
    print("Count is \(n)")
}
process(.weight(65))
process(.count(42))

Saída:

TEXT 📖 Somente leitura
Weight exceeds 70kg: 75.5
Not a count type
Count is 42

5. Enums Recursivos

Um enum recursivo é aquele cujos valores associados referenciam o próprio enum, adequado para expressar estruturas em árvore ou aninhadas.

(1) A Palavra-chave indirect

Use indirect para marcar um caso recursivo ou o enum inteiro, informando ao compilador que é necessário armazenamento indireto.

Sintaxe Descrição
indirect case expressao(Expressao) Caso recursivo único
indirect enum Expressao { ... } Enum inteiro permite recursão

▶ Exemplo: Avaliando uma Expressão Matemática

SWIFT
// ============================================
// Recursive enum: math expression tree
// ============================================
indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}
func evaluate(_ expr: ArithmeticExpression) -> Int {
    switch expr {
    case .number(let value):
        return value
    case .addition(let left, let right):
        return evaluate(left) + evaluate(right)
    case .multiplication(let left, let right):
        return evaluate(left) * evaluate(right)
    }
}
// Build the expression (3 + 5) * 2
let three = ArithmeticExpression.number(3)
let five = ArithmeticExpression.number(5)
let sum = ArithmeticExpression.addition(three, five)
let product = ArithmeticExpression.multiplication(sum, .number(2))
print("(3 + 5) * 2 = \(evaluate(product))")

Saída:

TEXT 📖 Somente leitura
(3 + 5) * 2 = 16

6. Exemplo Completo: Máquina de Estado de Pedido

SWIFT
// ============================================
// Full example: E-commerce order state machine
// Features: order state transitions + data processing
// ============================================
import Foundation
// 1. Order status enum (with associated values)
enum OrderStatus {
    case pending          // Pending payment
    case paid(Date)       // Paid (with payment time)
    case shipped(trackingNumber: String)  // Shipped (with tracking number)
    case delivered(Date)  // Delivered (with receipt time)
    case cancelled(reason: String)  // Cancelled (with reason)
    var description: String {
        switch self {
        case .pending: return "Pending"
        case .paid(let date): return "Paid (\(date.formatted()))"
        case .shipped(let tracking): return "Shipped (Tracking: \(tracking))"
        case .delivered(let date): return "Delivered (\(date.formatted()))"
        case .cancelled(let reason): return "Cancelled: \(reason)"
        }
    }
    var isFinalState: Bool {
        if case .delivered = self { return true }
        if case .cancelled = self { return true }
        return false
    }
}
// 2. Usage example
let now = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let statuses: [OrderStatus] = [
    .pending,
    .paid(now),
    .shipped(trackingNumber: "SF1234567890"),
    .delivered(now),
    .cancelled(reason: "Cancelled by user")
]
for status in statuses {
    let final = status.isFinalState ? " (Final)" : ""
    print("\(status.description)\(final)")
}

Saída:

TEXT 📖 Somente leitura
Pending
Paid (2026-07-30)
Shipped (Tracking: SF1234567890)
Delivered (2026-07-30) (Final)
Cancelled: Cancelled by user (Final)

❓ Perguntas Frequentes

P: Como escolher entre enums e structs? R: Enums são adequados para "estados mutuamente exclusivos" -- em qualquer ponto, apenas um pode estar ativo. Structs são adequadas para "múltiplas propriedades coexistentes" -- todas as propriedades existem simultaneamente. A escolha depende se seu modelo de dados é uma relação OU ou uma relação E. P: Valores associados e genéricos podem ser usados juntos? R: Sim. enum Optional<T> é um exemplo clássico de valores associados + genéricos: case none ou case some(T). Valores associados podem referenciar parâmetros genéricos. P: Por que os enums do Swift são mais poderosos que os enums do C/Java? R: Enums do Swift podem ter métodos, propriedades computadas, valores associados, definições recursivas e conformidade com protocolos. Enums do C/Java são meramente constantes inteiras nomeadas; enums do Swift são tipos de primeira classe completos. P: Quando devo obrigatoriamente usar indirect? R: Quando o tipo de valor associado de um enum referencia a si mesmo. Por exemplo, ExpressaoAritmetica.adicao tem valores associados do tipo ExpressaoAritmetica, formando uma referência recursiva que requer indirect. P: Devo sempre escrever default em um switch sobre um enum? R: É recomendado esgotar todos os casos e NÃO usar default. Dessa forma, quando você adicionar um novo caso no futuro, o compilador avisa sobre casos ausentes, prevenindo omissões acidentais. Mas se você genuinamente não precisa tratar todos os casos, pode adicionar default.


📖 Resumo


📝 Exercícios

  1. Básico: Defina um enum Semaforo com três casos: vermelho, amarelo, verde. Adicione uma propriedade computada duracao que retorna a duração em segundos de cada luz.
  2. Intermediário: Use valores associados para definir um enum Ou<L, R> (semelhante ao Result do Rust) com casos esquerda(L) e direita(R), e adicione um método map para transformar o valor direito.
  3. Desafio: Use um enum recursivo para implementar um tipo JSON (suportando null, bool, int, string, array, dicionário) e escreva uma função para formatar um valor enum JSON como uma string indentada.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%