---
title: "Kotlin Name-Based Destructuring: Guia Completo"
url: "https://kotlin.dev.br/blog/kotlin-name-based-destructuring-2026/"
markdown_url: "https://kotlin.dev.br/blog/kotlin-name-based-destructuring-2026.MD"
description: "Aprenda a usar name-based destructuring no Kotlin 2.3.20+. Sintaxe por nome, colchetes para posição e migração de data classes."
date: "2026-04-29"
author: "Karina Melo"
---

# Kotlin Name-Based Destructuring: Guia Completo

Aprenda a usar name-based destructuring no Kotlin 2.3.20+. Sintaxe por nome, colchetes para posição e migração de data classes.


A desestruturação é um dos recursos mais usados no Kotlin. Toda vez que você escreve `val (nome, idade) = pessoa`, está usando esse mecanismo. O problema é que, até agora, a desestruturação dependia exclusivamente da **posição** dos componentes — e isso gerava bugs sutis que só apareciam em produção.

A partir do **Kotlin 2.3.20**, o compilador introduziu a **desestruturação por nome** (name-based destructuring) como recurso experimental. A proposta KEEP-0438 define uma mudança fundamental na forma como o Kotlin resolve variáveis em declarações de desestruturação, trazendo segurança semântica sem sacrificar a ergonomia da linguagem.

Neste artigo, vamos explorar o problema que motivou essa mudança, a nova sintaxe, exemplos práticos e como preparar seu código para a migração.

## O problema da desestruturação por posição

Considere esta [data class](/tutoriais/data-classes-tutorial/) simples:

```kotlin
data class Pessoa(val nome: String, val endereco: String)

val (cidade, nome) = Pessoa("João", "Amsterdã")
```

Esse código compila sem erros. Mas `cidade` recebe `"João"` e `nome` recebe `"Amsterdã"` — exatamente o oposto do que os nomes das variáveis sugerem. O compilador não se importa com os nomes porque a desestruturação atual usa funções `component1()`, `component2()`, etc., que dependem exclusivamente da ordem.

### Quando o bug aparece de verdade

O cenário mais perigoso acontece quando alguém adiciona uma propriedade no meio de uma data class:

```kotlin
// Versão 1
data class Transacao(val valor: Double, val descricao: String)
val (valor, descricao) = transacao  // OK

// Versão 2 — alguém adiciona 'tipo' entre valor e descricao
data class Transacao(val valor: Double, val tipo: String, val descricao: String)
val (valor, descricao) = transacao  // QUEBROU: descricao agora recebe 'tipo'
```

Esse tipo de bug é especialmente perigoso em código de backend onde [data classes representam DTOs de APIs REST](/blog/kotlin-spring-boot/). A mudança silenciosa de semântica não gera erro de compilação — o tipo é compatível — mas corrompe dados em runtime.

Se você já viu esse tipo de problema em projetos reais, sabe que é difícil de diagnosticar. Nosso guia sobre [testes com JUnit5 e MockK](/blog/kotlin-testes-junit5-mockk-guia/) ajuda a montar cenários que capturam regressões desse tipo, mas a solução definitiva é corrigir o mecanismo de linguagem.

## Como funciona a desestruturação por nome

Com a flag do compilador habilitada, a desestruturação por nome resolve variáveis pelo **nome da propriedade** em vez da posição. A sintaxe usa parênteses com `val` explícito:

```kotlin
data class Transacao(val valor: Double, val tipo: String, val descricao: String)

// Desestruturação por nome — ordem não importa
val (val descricao, val valor) = transacao
// descricao = transacao.descricao (correto!)
// valor = transacao.valor (correto!)
```

O compilador faz o match entre o nome da variável e o nome da propriedade. A ordem na declaração não importa mais. Isso elimina toda a classe de bugs descrita acima.

### Renomeando variáveis

Quando você precisa usar um nome diferente da propriedade, a sintaxe suporta aliases:

```kotlin
val (val desc = descricao, val amount = valor) = transacao
// desc recebe transacao.descricao
// amount recebe transacao.valor
```

Isso é útil quando o nome da propriedade não é ideal para o contexto local ou quando há conflito de nomes com variáveis existentes no escopo.

## Nova sintaxe de colchetes para posição

A proposta também introduz **colchetes** para desestruturação posicional explícita. Isso é importante para tipos onde a ordem dos elementos é o que importa, como `Pair`, `Triple`, listas e mapas:

```kotlin
// Posicional com colchetes — para Pair, Triple, etc.
val [primeiro, segundo] = Pair("Kotlin", "Java")

// Em loops de Map
for ([chave, valor] in mapaDeCidades) {
    println("$chave -> $valor")
}
```

A distinção visual entre parênteses (nome) e colchetes (posição) torna o código auto-documentado. Quem lê sabe imediatamente qual estratégia está sendo usada.

### Comparação direta

```kotlin
data class Config(val host: String, val port: Int, val debug: Boolean)

val config = Config("localhost", 8080, true)

// Por NOME — match por propriedade (nova sintaxe)
val (val debug, val host) = config
// debug = true, host = "localhost"

// Por POSIÇÃO — match por componente (colchetes)
val [primeiro, segundo] = config
// primeiro = "localhost", segundo = 8080
```

## Habilitando no seu projeto

Para usar a desestruturação por nome no Kotlin 2.3.20+, adicione a flag do compilador no [Gradle](/guias/guia-kotlin-gradle/):

```kotlin
// build.gradle.kts
kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xname-based-destructuring=only-syntax")
    }
}
```

A flag aceita três modos progressivos:

| Modo | Comportamento |
|------|-------------|
| `only-syntax` | Habilita a sintaxe `val (val x, val y)` sem alterar código existente |
| `name-mismatch` | Emite warnings quando nomes de variáveis não correspondem aos da data class |
| `complete` | Ativa o modo completo com parênteses para nome e colchetes para posição |

Para projetos existentes, comece com `only-syntax` para experimentar sem risco. Depois evolua para `name-mismatch` para identificar desestruturações potencialmente incorretas no código atual.

## Exemplos práticos em cenários reais

### DTO de API com Spring Boot

```kotlin
data class PedidoDTO(
    val id: Long,
    val cliente: String,
    val itens: List<ItemDTO>,
    val valorTotal: Double,
    val status: String
)

fun processarPedido(dto: PedidoDTO) {
    // Por nome — extraímos apenas o que precisamos, na ordem que queremos
    val (val status, val valorTotal, val cliente) = dto

    when (status) {
        "PENDENTE" -> enviarNotificacao(cliente, valorTotal)
        "PAGO" -> iniciarEntrega(dto)
        "CANCELADO" -> estornar(cliente, valorTotal)
    }
}
```

A vantagem aqui é clara: se alguém adicionar uma nova propriedade ao `PedidoDTO` amanhã, o código de desestruturação continua funcionando corretamente. Isso é especialmente relevante em projetos de [microserviços com Kotlin](/guias/guia-kotlin-microservicos/) onde múltiplos times evoluem DTOs compartilhados.

### Desestruturação em lambdas

A nova sintaxe funciona dentro de lambdas, o que é útil com [collections](/tutoriais/collections-kotlin/) e [Flow](/blog/kotlin-flow/):

```kotlin
data class Metrica(val nome: String, val valor: Double, val unidade: String)

val metricas = listOf(
    Metrica("cpu_usage", 75.3, "%"),
    Metrica("memory_mb", 2048.0, "MB"),
    Metrica("requests_per_sec", 1200.0, "req/s")
)

// Desestruturação por nome na lambda
metricas
    .filter { (val valor) -> valor > 100 }
    .forEach { (val nome, val valor, val unidade) ->
        println("Alerta: $nome = $valor$unidade")
    }
```

### Combinando com sealed classes

```kotlin
sealed class Resultado {
    data class Sucesso(val dados: String, val timestamp: Long) : Resultado()
    data class Erro(val mensagem: String, val codigo: Int) : Resultado()
}

fun tratarResultado(resultado: Resultado) {
    when (resultado) {
        is Resultado.Sucesso -> {
            val (val dados, val timestamp) = resultado
            salvarCache(dados, timestamp)
        }
        is Resultado.Erro -> {
            val (val codigo, val mensagem) = resultado
            log.error("Erro $codigo: $mensagem")
        }
    }
}
```

Com [sealed classes](/blog/sealed-classes-kotlin/), a desestruturação por nome torna o pattern matching mais legível. A ordem dos campos na declaração reflete a importância semântica no contexto, não a posição na data class.

## Funciona com classes normais?

Sim, desde que a classe exponha propriedades públicas. A desestruturação por nome não depende de `componentN()`:

```kotlin
class Configuracao(
    val ambiente: String,
    val versao: String,
    val porta: Int
) {
    val urlCompleta: String get() = "$ambiente:$porta/v$versao"
}

val (val ambiente, val porta) = Configuracao("prod", "2.0", 443)
// ambiente = "prod", porta = 443
```

Isso abre possibilidades para classes que antes não suportavam desestruturação sem implementar `operator fun componentN()` manualmente. Para quem trabalha com [extension functions](/blog/extension-functions-kotlin/), isso significa que a desestruturação agora funciona com qualquer classe que tenha propriedades públicas.

## Plano de migração da JetBrains

A KEEP-0438 define um plano de migração em três fases:

**Fase 1** (atual): a nova sintaxe coexiste com a antiga. Parênteses sem `val` continuam sendo posicionais. A flag `only-syntax` permite usar a nova sintaxe sem efeitos colaterais.

**Fase 2**: o compilador emite warnings para desestruturações posicionais onde os nomes das variáveis não correspondem às propriedades. Isso ajuda a identificar código potencialmente incorreto.

**Fase 3** (futuro): `val (x, y) = e` passa a significar desestruturação por nome por padrão. A desestruturação posicional migra para a sintaxe de colchetes `[x, y]`.

Para projetos que usam [version catalogs no Gradle](/blog/gradle-version-catalog-kotlin-2026/), a recomendação é fixar a flag do compilador no catálogo centralizado para garantir consistência entre módulos.

## Impacto na compatibilidade binária

Um benefício menos óbvio da desestruturação por nome é a **estabilidade da API binária**. Com a abordagem posicional, adicionar uma propriedade no meio de uma data class quebra código que faz desestruturação. Com a abordagem por nome, a adição de novos campos não afeta código existente — apenas os campos explicitamente nomeados são extraídos.

Isso é particularmente importante para autores de bibliotecas. Se você mantém uma lib Kotlin publicada no Maven Central, a desestruturação por nome permite evoluir data classes sem quebrar a compatibilidade com consumidores. Para quem trabalha com [serialização avançada](/blog/kotlin-serialization-avancada-polimorfismo-2026/), essa estabilidade complementa o versionamento de schemas.

## Conclusão

A desestruturação por nome resolve um problema real que existia desde o Kotlin 1.0. A dependência da posição sempre foi uma fonte de bugs silenciosos, especialmente em equipes grandes onde data classes evoluem com frequência.

A recomendação prática: habilite `only-syntax` no seu projeto hoje para experimentar. Depois migre para `name-mismatch` para encontrar desestruturações suspeitas no código existente. Quando a Fase 3 chegar em uma release futura, seu código já estará preparado.

Se você está acompanhando as novidades do Kotlin em 2026, esse recurso se encaixa na mesma filosofia de segurança de tipo que motivou [null safety](/blog/null-safety-kotlin/), [value classes](/blog/kotlin-value-classes/) e [explicit backing fields](/blog/kotlin-explicit-backing-fields-2026/). O Kotlin continua priorizando código correto por construção. Em outras linguagens do ecossistema de sistemas, <a href="https://rustlang.com.br/blog/pattern-matching-rust-match/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Rust resolve desestruturação de structs por nome desde sua primeira versão estável</a>, e a inspiração é clara na proposta da KEEP-0438. Linguagens como <a href="https://python.dev.br/blog/python-unpacking-desempacotamento/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'python.dev.br' })">Python com seu unpacking</a> e <a href="https://golang.com.br/blog/golang-structs-metodos/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go com acesso explícito a campos de structs</a> adotam abordagens diferentes, mas o objetivo é o mesmo: evitar erros de posição.

Para ver como os novos componentes de layout do Compose se beneficiam de data classes com desestruturação segura, confira nosso artigo sobre [Grid, FlexBox e Media Query no Compose](/blog/jetpack-compose-grid-flexbox-media-query-2026/).

---

## Perguntas frequentes

### A desestruturação por nome funciona com Pair e Triple?

Pair e Triple continuam usando desestruturação posicional com a nova sintaxe de colchetes: `val [primeiro, segundo] = pair`. Como esses tipos representam tuplas genéricas sem nomes semânticos, a abordagem posicional com colchetes é a mais adequada.

### Preciso reescrever todo meu código existente?

Nao. O modo `only-syntax` permite adotar a nova sintaxe gradualmente em código novo sem afetar código existente. A migração completa para a Fase 3 acontecerá em uma release futura com período de deprecação e ferramentas automáticas de migração no IntelliJ IDEA.

### A desestruturação por nome é mais lenta que a posicional?

Nao. Ambas as formas geram o mesmo bytecode no JVM. A resolução por nome acontece em tempo de compilação — o compilador traduz `val (val nome) = pessoa` para `val nome = pessoa.nome`, sem overhead em runtime.

### Posso misturar desestruturação por nome e por posição no mesmo arquivo?

Sim. Com a flag `only-syntax`, parênteses sem `val` continuam sendo posicionais e parênteses com `val` são por nome. Isso permite migração gradual dentro do mesmo arquivo ou módulo.
