O que e Destructuring em Kotlin?

Destructuring (desestruturacao) permite decompor um objeto em várias variaveis numa única declaracao. Em vez de acessar cada propriedade separadamente, você extrai tudo de uma vez. E prático, limpo é muito usado no dia a dia.

Imagine que você recebe uma encomenda com vários itens dentro de uma caixa. Em vez de abrir a caixa e tirar item por item chamando pelo nome da caixa toda vez, o destructuring e como abrir a caixa e já colocar cada item diretamente na prateleira certa. Voce ganha clareza e economia de código.

Esse recurso funciona com data classes, pares, triplas, mapas e qualquer classe que implemente as funções componentN(). E uma ferramenta essencial para quem trabalha com colecoes e lambdas em Kotlin.

Sintaxe básica com Data Class

data class Endereco(val rua: String, val cidade: String, val estado: String)

fun main() {
    val endereco = Endereco("Rua das Flores", "Recife", "PE")

    val (rua, cidade, estado) = endereco
    println("$rua, $cidade - $estado")
    // Rua das Flores, Recife - PE
}

Funciona porque data classes geram automaticamente as funções component1(), component2(), etc.

Destructuring em Maps

Uma das situacoes mais comuns e iterar sobre mapas:

fun main() {
    val capitais = mapOf(
        "SP" to "Sao Paulo",
        "RJ" to "Rio de Janeiro",
        "BA" to "Salvador"
    )

    for ((sigla, capital) in capitais) {
        println("$sigla -> $capital")
    }
}

Bem mais legivel do que acessar entry.key e entry.value, concorda?

Destructuring em lambdas

fun main() {
    val pessoas = listOf(
        Pair("Ana", 25),
        Pair("Bruno", 30),
        Pair("Carla", 28)
    )

    pessoas.forEach { (nome, idade) ->
        println("$nome tem $idade anos")
    }
}

Ignorando variaveis com _

Se não precisa de algum componente, use _ pra ignorar:

data class Transacao(val id: String, val valor: Double, val data: String)

fun main() {
    val transacao = Transacao("TX-001", 150.0, "2026-02-15")

    val (_, valor, _) = transacao
    println("Valor: R$ $valor") // Valor: R$ 150.0
}

Criando destructuring em classes proprias

Para classes que não sao data class, basta implementar as funções operator componentN():

class Coordenada(val latitude: Double, val longitude: Double) {
    operator fun component1() = latitude
    operator fun component2() = longitude
}

fun main() {
    val (lat, lng) = Coordenada(-8.0476, -34.8770)
    println("Lat: $lat, Lng: $lng")
}

Retornando múltiplos valores

Destructuring combina bem com Pair e Triple pra retornar vários valores de uma função:

fun dividir(a: Int, b: Int): Pair<Int, Int> {
    return Pair(a / b, a % b)
}

fun main() {
    val (quociente, resto) = dividir(17, 5)
    println("Quociente: $quociente, Resto: $resto")
}

Destructuring com resultados de funções da stdlib

Destructuring se integra muito bem com funções da biblioteca padrão do Kotlin, como withIndex() e partition():

fun main() {
    val frutas = listOf("manga", "acerola", "caju", "goiaba", "pitanga")

    // withIndex retorna IndexedValue, que suporta destructuring
    for ((indice, fruta) in frutas.withIndex()) {
        println("$indice: $fruta")
    }

    // partition retorna um Pair de listas
    val (curtas, longas) = frutas.partition { it.length <= 4 }
    println("Nomes curtos: $curtas")  // [caju]
    println("Nomes longos: $longas")  // [manga, acerola, goiaba, pitanga]
}

Destructuring em blocos try-catch com Result

Voce pode usar destructuring para lidar com respostas de APIs ou operações que retornam dados estruturados:

data class RespostaApi(val sucesso: Boolean, val mensagem: String, val dados: Map<String, Any>)

fun buscarUsuario(id: Int): RespostaApi {
    return if (id > 0) {
        RespostaApi(true, "Encontrado", mapOf("nome" to "Maria", "idade" to 32))
    } else {
        RespostaApi(false, "Nao encontrado", emptyMap())
    }
}

fun main() {
    val (sucesso, mensagem, dados) = buscarUsuario(1)
    if (sucesso) {
        println("$mensagem: $dados")
    }
}

Casos de Uso no Mundo Real

  • Processamento de arquivos CSV: ao ler linhas de um CSV, você pode desestruturar cada linha em variaveis nomeadas como val (nome, email, telefone) = linha.split(","), tornando o código muito mais legivel.
  • Respostas de APIs: quando uma função retorna um par de status e corpo da resposta, destructuring permite extrair ambos numa única linha.
  • Iteracao sobre bancos de dados: ao percorrer resultados de queries que retornam mapas ou data classes, você acessa cada campo diretamente.
  • Testes unitarios: ao validar objetos complexos, desestruturar facilita a comparacao de campos individuais sem criar variaveis intermediarias.

Boas Praticas

  • Use destructuring quando os nomes das variaveis deixam claro o que cada componente representa. Se os nomes não ajudam, considere acessar as propriedades diretamente.
  • Prefira data classes em vez de Pair e Triple quando o significado dos campos importa. Pair("Ana", 25) não diz o que e cada campo; Pessoa("Ana", 25) sim.
  • Use _ para ignorar componentes que você não precisa, evitando variaveis não utilizadas.
  • Nao desestruture objetos com muitos campos (mais de 4 ou 5) numa única declaracao, pois fica difícil acompanhar a ordem.

Erros Comuns

  • Confundir a ordem dos componentes: o destructuring segue a ordem de declaracao das propriedades. Se você inverter val (cidade, rua) = endereco, vai receber os valores trocados sem nenhum erro de compilação.
  • Tentar desestruturar classes que não sao data class: classes comuns não geram componentN() automaticamente. Voce precisa implementar essas funções manualmente ou usar uma data class.
  • Ignorar o tipo: se você desestruturar um Pair<String, Int> e tratar o segundo valor como String, tera um erro em tempo de execução.
  • Esquecer o val ou var: a declaracao (a, b) = par sem val na frente não funciona como declaracao; e necessário escrever val (a, b) = par.

Perguntas Frequentes

Destructuring funciona com classes que não sao data class? Sim, desde que você implemente as funções operator fun componentN() na classe. Data classes geram essas funções automaticamente, mas nada impede você de cria-las manualmente em qualquer classe.

Posso usar destructuring com sealed classes? Sim, desde que a sealed class ou suas subclasses sejam data classes ou implementem as funções componentN(). Geralmente você faz o when primeiro e depois desestrutura dentro de cada branch.

Existe limite de componentes no destructuring? Nao existe um limite imposto pela linguagem, mas na prática, data classes geram component1() até componentN() para todas as propriedades do construtor primario. O bom senso recomenda não ultrapassar 4 ou 5 componentes.

Destructuring cria copias dos valores ou referência o objeto original? Destructuring cria variaveis independentes com os valores retornados pelas funções componentN(). Para tipos primitivos, sao copias. Para objetos, sao referências ao mesmo objeto em memória.

Destructuring e um recurso simples que faz uma diferenca enorme na legibilidade do código Kotlin.