---
title: "Receiver em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/receiver/"
markdown_url: "https://kotlin.dev.br/glossario/receiver.MD"
description: "Entenda o que é Receiver em Kotlin, como funciona em extension functions, lambdas with receiver e DSLs."
date: "2025-08-17"
author: "Karina Melo"
---

# Receiver em Kotlin: O que É e Como Funciona | Kotlin Brasil

Entenda o que é Receiver em Kotlin, como funciona em extension functions, lambdas with receiver e DSLs.


## O que é Receiver em Kotlin?

O **receiver** é o objeto sobre o qual uma função opera, acessivel dentro da função através da palavra-chave `this`. Em Kotlin, o conceito de receiver aparece em **extension functions**, **lambdas with receiver** e **scope functions**, sendo fundamental para a criação de APIs fluentes e DSLs.

Em uma função normal, os parametros são explicitamente nomeados. Com um receiver, o objeto esta implicito no escopo da função, permitindo acessar suas propriedades e métodos diretamente sem qualificacao.

### Receiver em extension functions

O exemplo mais comum de receiver e em extension functions:

```kotlin
fun String.contarVogais(): Int {
    // 'this' se refere ao String sobre o qual a funcao foi chamada
    return this.count { it in "aeiouAEIOU" }
}

fun main() {
    val texto = "Kotlin Brasil"
    println(texto.contarVogais()) // 5
}
```

Aqui, `String` e o tipo do receiver. Dentro da função, `this` aponta para a instancia de `String` sobre a qual `contarVogais()` foi chamado. O `this` pode ser omitido:

```kotlin
fun String.contarVogais(): Int {
    return count { it in "aeiouAEIOU" } // 'this' implicito
}
```

### Lambda with receiver

Uma lambda with receiver e uma lambda que tem acesso ao receiver como `this`. A sintaxe do tipo e `TipoReceiver.() -> TipoRetorno`:

```kotlin
fun construirMensagem(builder: StringBuilder.() -> Unit): String {
    val sb = StringBuilder()
    sb.builder() // Chama a lambda com sb como receiver
    return sb.toString()
}

fun main() {
    val mensagem = construirMensagem {
        // Dentro dessa lambda, 'this' e o StringBuilder
        append("Ola, ")
        append("Kotlin!")
        appendLine()
        append("Tudo bem?")
    }
    println(mensagem)
}
```

A lambda `builder` tem `StringBuilder` como receiver, entao dentro dela você pode chamar `append`, `appendLine` e outros métodos diretamente, como se estivesse dentro de um método da classe.

### Scope functions e receivers

As scope functions do Kotlin usam diferentes tipos de receiver:

```kotlin
data class Pessoa(var nome: String, var idade: Int)

fun main() {
    val pessoa = Pessoa("Ana", 25)

    // apply: receiver e 'this', retorna o objeto
    pessoa.apply {
        nome = "Ana Maria"  // this.nome
        idade = 26           // this.idade
    }

    // with: receiver e 'this', retorna o resultado da lambda
    val descricao = with(pessoa) {
        "$nome tem $idade anos" // this.nome, this.idade
    }

    // run: receiver e 'this', retorna o resultado da lambda
    val resultado = pessoa.run {
        "$nome ($idade)"
    }

    // let: parametro e 'it', nao usa receiver
    pessoa.let { p ->
        println("${p.nome} tem ${p.idade} anos")
    }

    // also: parametro e 'it', retorna o objeto
    pessoa.also {
        println("Pessoa: ${it.nome}")
    }
}
```

`apply`, `with` e `run` usam lambda with receiver (`this`). `let` e `also` usam lambda com parametro (`it`).

### Criando DSLs com receiver

O poder real dos receivers aparece na criação de DSLs (Domain Specific Languages):

```kotlin
class HtmlBuilder {
    private val elementos = mutableListOf<String>()

    fun h1(texto: String) {
        elementos.add("<h1>$texto</h1>")
    }

    fun p(texto: String) {
        elementos.add("<p>$texto</p>")
    }

    fun ul(configurar: ListaBuilder.() -> Unit) {
        val builder = ListaBuilder()
        builder.configurar()
        elementos.add(builder.construir())
    }

    fun construir(): String = elementos.joinToString("\n")
}

class ListaBuilder {
    private val itens = mutableListOf<String>()

    fun li(texto: String) {
        itens.add("<li>$texto</li>")
    }

    fun construir(): String {
        val conteudo = itens.joinToString("\n  ")
        return "<ul>\n  $conteudo\n</ul>"
    }
}

fun html(configurar: HtmlBuilder.() -> Unit): String {
    val builder = HtmlBuilder()
    builder.configurar()
    return builder.construir()
}

fun main() {
    val pagina = html {
        h1("Kotlin Brasil")
        p("Aprenda Kotlin em português.")
        ul {
            li("Coroutines")
            li("Flow")
            li("Compose")
        }
    }
    println(pagina)
}
```

Cada bloco `{ }` tem um receiver diferente, e os métodos disponiveis mudam conforme o contexto. Isso cria uma sintaxe que parece uma linguagem própria.

### @DslMarker para controle de escopo

Sem controle, receivers de escopos externos podem vazar para escopos internos:

```kotlin
@DslMarker
annotation class HtmlDsl

@HtmlDsl
class HtmlBuilder { /* ... */ }

@HtmlDsl
class ListaBuilder { /* ... */ }

// Agora, dentro de ul { }, voce NAO pode acessar h1() ou p()
// Isso impede erros de escopo na DSL
```

O `@DslMarker` restringe o acesso a receivers de escopos externos, tornando a DSL mais segura e previsivel.

### Receiver em funções de extensao de tipos genericos

```kotlin
fun <T> T.tambem(bloco: (T) -> Unit): T {
    bloco(this)
    return this
}

fun <T> T.executar(bloco: T.() -> Unit): T {
    this.bloco()
    return this
}
```

A diferenca entre `(T) -> Unit` (parametro) e `T.() -> Unit` (receiver) e sutil mas importante:

```kotlin
// Com parametro: acesso via 'it' ou nome do parametro
"texto".tambem { valor -> println(valor.length) }

// Com receiver: acesso via 'this' (implicito)
"texto".executar { println(length) }
```

### Múltiplos receivers

Kotlin permite que uma função tenha um receiver de extensao e um dispatch receiver (da classe):

```kotlin
class Logger {
    fun String.logInfo() {
        // 'this' se refere ao String (extension receiver)
        // 'this@Logger' se refere ao Logger (dispatch receiver)
        println("[INFO] $this")
    }
}

fun main() {
    val logger = Logger()
    with(logger) {
        "Mensagem de teste".logInfo() // [INFO] Mensagem de teste
    }
}
```

### Quando usar receivers

- **Extension functions**: para adicionar funcionalidade a tipos existentes sem heranca.
- **DSLs**: para criar APIs que leem como linguagem natural.
- **Builders**: para construir objetos complexos com sintaxe fluente.
- **Scope functions**: para operações rápidas em objetos sem criar variaveis intermediarias.
- **Configuração**: para blocos de configuração onde o contexto e claro e os métodos disponiveis são limitados.

### Casos de Uso no Mundo Real

1. **DSLs de construcao de UI**: frameworks como Jetpack Compose e bibliotecas de HTML (kotlinx.html) usam lambdas with receiver extensivamente para criar interfaces declarativas. Cada bloco de construcao (Column, Row, Box) recebe uma lambda cujo receiver e o escopo de layout correspondente, permitindo que modificadores e filhos sejam adicionados de forma natural.

2. **configuração de clientes HTTP**: bibliotecas como Ktor usam receivers para configurar requisicoes HTTP de forma fluente. O bloco de configuração do cliente, rotas, autenticação e plugins usam lambdas with receiver, permitindo que cada nivel de configuração exponha apenas os métodos relevantes ao contexto.

3. **Builders de consultas de banco de dados**: ORMs como Exposed usam receivers para construir queries SQL de forma type-safe. Dentro de um bloco `transaction`, o receiver fornece acesso a operações de banco; dentro de `select`, o receiver muda para expor operações de filtragem e projecao.

4. **Extension functions em projetos corporativos**: equipes adicionam funções de extensao a classes de dominio para encapsular lógica recorrente (formatacao, validacao, conversao) sem alterar as classes originais, especialmente útil quando as classes vem de bibliotecas de terceiros.

### Boas Praticas

- **Use `@DslMarker` ao criar DSLs com receivers aninhados**: sem essa anotacao, receivers de escopos externos vazam para escopos internos, permitindo chamadas de métodos que não fazem sentido no contexto atual e gerando bugs sutis.
- **Prefira `this` explicito em escopos ambiguos**: quando há múltiplos receivers em escopos aninhados, usar `this@NomeDaFuncao` torna o código mais claro e evita que o receiver errado seja usado acidentalmente.
- **Nao polua tipos comuns com muitas extension functions**: adicionar dezenas de extensoes a `String`, `Int` ou `List` dificulta a descoberta de funcionalidade e pode gerar conflitos de nome. Agrupe extensoes relacionadas em arquivos específicos e com boa documentação.
- **Use lambda with receiver para APIs de configuração**: quando sua função recebe um bloco de configuração, declarar o parametro como `Config.() -> Unit` em vez de `(Config) -> Unit` torna o código do chamador mais limpo e idiomatico.
- **Evite extension functions com efeitos colaterais inesperados**: uma função `String.salvarNoBanco()` viola o princípio de menor surpresa. Extension functions devem ter comportamento previsivel e coerente com o tipo que estendem.

### Perguntas Frequentes

**P: Extension functions podem acessar membros privados da classe que estendem?**
R: Nao. Extension functions tem acesso apenas a membros publicos e `internal` do tipo receptor. Elas sao resolvidas estaticamente e não alteram a classe original. Se você precisa acessar membros privados, use uma função membro da própria classe.

**P: Qual a diferenca entre `T.() -> Unit` e `(T) -> Unit`?**
R: `T.() -> Unit` e uma lambda with receiver, onde dentro da lambda você acessa `T` via `this` (implicito). `(T) -> Unit` e uma lambda com parametro, onde você acessa `T` via nome do parametro ou `it`. Funcionalmente sao equivalentes, mas a versão com receiver produz código mais limpo em contextos de builder e DSL.

**P: O que sao Context Receivers e como se relacionam com receivers normais?**
R: Context Receivers sao um recurso experimental do Kotlin que permite declarar múltiplos receivers implicitos para uma função, sem precisar encadear extension functions. Enquanto um receiver normal e único (`fun String.algo()`), context receivers permitem que a função exija múltiplos contextos simultaneamente (`context(Logger, Database) fun processar()`).

**P: Extension functions sao resolvidas em tempo de compilação ou execução?**
R: Em tempo de compilação (dispatch estático). Isso significa que se uma classe filha e uma classe pai ambas tem uma extension function com a mesma assinatura, a função chamada depende do tipo declarado da variavel, não do tipo real do objeto em tempo de execução.

### Erros comuns

1. **Receiver errado em escopos aninhados**: quando você tem lambdas aninhadas com diferentes receivers, `this` se refere ao mais interno. Use `this@NomeDaFuncao` para acessar receivers externos.

2. **Abusar de extension functions**: adicionar muitas extensions a tipos comuns como `String` ou `Int` polui o namespace e dificulta a descoberta de funcionalidade.

3. **Nao usar @DslMarker**: sem essa anotacao, DSLs permitem chamadas de métodos de escopos externos, levando a erros sutis.

4. **Confundir `T.() -> Unit` com `(T) -> Unit`**: a primeira e uma lambda with receiver (acesso via `this`); a segunda e uma lambda com parametro (acesso via nome do parametro ou `it`).

5. **Esquecer que extension functions não tem acesso a membros privados**: o receiver `this` da acesso apenas a membros publicos e internos do tipo, não a membros privados ou protegidos.

### Termos relacionados

- **Extension Function**: função que adiciona métodos a um tipo usando receiver.
- **Context Receiver**: recurso experimental que permite múltiplos receivers implícitos.
- **Scope Functions**: `let`, `run`, `with`, `apply`, `also` -- funções que manipulam receivers.
- **DSL**: Domain Specific Language, construida usando lambdas with receiver.
- **this**: palavra-chave que referência o receiver atual.
- **Lambda**: expressao funcional que pode ter receiver (`T.() -> Unit`).

Receivers são um dos conceitos mais poderosos e distintos do Kotlin. Eles permitem que o código expresse intencao de forma clara e concisa, transformando operações complexas em blocos legiveis que parecem parte da linguagem. Dominar receivers e dominar a essencia do Kotlin idiomatico.
