---
title: "Scope Functions em Kotlin: Guia Completo | Kotlin Brasil"
url: "https://kotlin.dev.br/blog/scope-functions-kotlin/"
markdown_url: "https://kotlin.dev.br/blog/scope-functions-kotlin.MD"
description: "Domine as scope functions do Kotlin: let, run, with, apply e also. Guia completo em português com exemplos práticos e quando usar cada uma."
date: "2026-03-23"
author: "Karina Melo"
---

# Scope Functions em Kotlin: Guia Completo | Kotlin Brasil

Domine as scope functions do Kotlin: let, run, with, apply e also. Guia completo em português com exemplos práticos e quando usar cada uma.


As scope functions sao um dos recursos mais usados e, ao mesmo tempo, mais confusos de Kotlin. Existem cinco delas — `let`, `run`, `with`, `apply` e `also` — e todas fazem basicamente a mesma coisa: executam um bloco de codigo no contexto de um objeto. A diferença está nos detalhes: como o objeto é referenciado e o que a funcao retorna.

Neste guia, vamos desmistificar cada uma com exemplos práticos do mundo real.

## O que são scope functions?

Scope functions são funcoes da biblioteca padrão do Kotlin que criam um **escopo temporário** para um objeto. Dentro desse escopo, voce acessa o objeto sem precisar repetir seu nome. Elas existem para tornar o código mais conciso e legível — especialmente quando voce precisa fazer várias operacões em sequência sobre o mesmo objeto.

Todas as cinco funcoes fazem essencialmente o mesmo: executam um bloco de código em um objeto. O que muda entre elas sao dois fatores:

1. **Como o objeto é referenciado**: via `this` (receptor) ou `it` (argumento)
2. **O que é retornado**: o resultado da lambda ou o próprio objeto

## Tabela comparativa

Antes de mergulhar nos detalhes, aqui está o resumo que voce vai consultar sempre:

| Funcao | Referência ao objeto | Valor de retorno | Caso de uso principal |
|---|---|---|---|
| `let` | `it` | Resultado da lambda | Transformacoes, null-safety |
| `run` | `this` | Resultado da lambda | Inicializacao + computacao |
| `with` | `this` | Resultado da lambda | Operacoes em bloco |
| `apply` | `this` | Objeto contexto | Configuracao de objetos |
| `also` | `it` | Objeto contexto | Efeitos colaterais |

Guarde essa tabela. A chave é entender que `this` permite chamar metodos diretamente (sem prefixo), enquanto `it` é um nome explícito para o objeto.

## let: transformacao e null-safety

A funcao `let` é provavelmente a scope function mais usada em Kotlin. Ela recebe o objeto como argumento (`it`) e retorna o resultado da lambda.

O caso de uso classico é com o operador de chamada segura (`?.`):

```kotlin
val nome: String? = obterNomeDoBanco()

// Sem let — verboso
if (nome != null) {
    val formatado = nome.trim().uppercase()
    println(formatado)
}

// Com let — idiomático
nome?.let {
    val formatado = it.trim().uppercase()
    println(formatado)
}
```

O `?.let` só executa o bloco se o valor não for nulo. E uma alternativa elegante ao `if (x != null)`.

Outro uso comum é para transformacoes em cadeia:

```kotlin
val resultado = listaDePedidos
    .filter { it.status == Status.PENDENTE }
    .let { pedidosPendentes ->
        // Renomear 'it' para clareza
        println("Encontrados ${pedidosPendentes.size} pedidos pendentes")
        pedidosPendentes.sortedBy { it.data }
    }
```

Note que voce pode renomear `it` para um nome mais descritivo — algo que nao é possível com `this`.

## run: inicializacao + computacao

A funcao `run` é como o `let`, mas usa `this` em vez de `it`. Isso significa que voce pode chamar metodos do objeto diretamente, sem prefixo. Ela retorna o resultado da lambda.

```kotlin
val resultado = servico.run {
    // 'this' é o servico — chamadas diretas
    configurar(timeout = 5000)
    conectar()
    executarQuery("SELECT * FROM usuarios")
}
// resultado = retorno de executarQuery()
```

O `run` tambem tem uma versao sem receptor, util para limitar escopo de variaveis:

```kotlin
val hexColor = run {
    val r = (0..255).random()
    val g = (0..255).random()
    val b = (0..255).random()
    String.format("#%02x%02x%02x", r, g, b)
}
// r, g, b não vazam para o escopo externo
```

Esse padrão é excelente para computacoes que precisam de variaveis temporárias sem poluir o escopo ao redor.

## with: operacoes em bloco sem null-safety

A funcao `with` é quase identica ao `run`, mas com uma diferença importante: ela não é uma [extension function](/blog/extension-functions-kotlin/). Voce passa o objeto como argumento:

```kotlin
val descricao = with(usuario) {
    // 'this' é o usuario
    "Nome: $nome, Email: $email, Cidade: $cidade"
}
```

O `with` é ideal quando voce tem um objeto não-nulo e quer fazer várias operacoes nele:

```kotlin
with(canvas) {
    drawColor(Color.WHITE)
    drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
    drawText("Kotlin", 100f, 200f, textPaint)
    drawCircle(150f, 300f, 50f, circlePaint)
}
```

A limitacao do `with` é que ele não funciona com null-safety (`?.`). Se o objeto pode ser nulo, use `run` ou `let` no lugar.

## apply: configuracao de objetos

A funcao `apply` usa `this` como referência ao objeto, mas diferente do `run`, ela **retorna o próprio objeto** em vez do resultado da lambda. Isso a torna perfeita para configurar objetos no estilo builder:

```kotlin
val requisicao = HttpRequest().apply {
    url = "https://api.exemplo.com/dados"
    method = "POST"
    headers["Content-Type"] = "application/json"
    headers["Authorization"] = "Bearer $token"
    timeout = 30_000
    body = """{"chave": "valor"}"""
}
// requisicao é o HttpRequest configurado
```

O `apply` é extremamente comum em código Android com Kotlin:

```kotlin
val intent = Intent(context, DetalheActivity::class.java).apply {
    putExtra("PRODUTO_ID", produto.id)
    putExtra("PRODUTO_NOME", produto.nome)
    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(intent)
```

Sempre que voce precisar criar um objeto e configurar suas propriedades em sequência, `apply` é a escolha certa.

## also: efeitos colaterais

A funcao `also` é a contraparte do `apply`: ela retorna o próprio objeto, mas usa `it` em vez de `this`. Ela é ideal para efeitos colaterais — acoes que voce quer executar "de passagem" sem alterar a cadeia de operacoes:

```kotlin
val usuario = criarUsuario("Maria")
    .also { println("Usuario criado: ${it.nome}") }
    .also { analytics.registrar("novo_usuario", it.id) }
    .also { validador.verificar(it) }
```

O `also` é perfeito para logging e depuracao em cadeias de chamadas:

```kotlin
val numeros = listOf(1, 5, 3, 2, 4)
    .also { println("Original: $it") }
    .sorted()
    .also { println("Ordenado: $it") }
    .reversed()
    .also { println("Invertido: $it") }
```

Voce pode inserir chamadas `also` em qualquer ponto de uma cadeia para inspecionar valores intermediários — e removê-las depois sem afetar a lógica.

## Quando usar qual: arvore de decisao

Na dúvida sobre qual scope function escolher, siga este fluxo:

1. **Precisa tratar nulidade?** Use `?.let { }`
2. **Quer configurar propriedades de um objeto?** Use `apply`
3. **Quer fazer efeitos colaterais (log, validacao)?** Use `also`
4. **Quer computar algo usando metodos do objeto?** Use `run`
5. **Tem um objeto não-nulo e quer operar nele em bloco?** Use `with`

Outra forma de pensar:

- Precisa do resultado da lambda? `let`, `run` ou `with`
- Precisa do objeto de volta? `apply` ou `also`
- Quer chamar metodos direto (sem `it.`)? `run`, `with` ou `apply`
- Quer um nome explícito para o objeto? `let` ou `also`

## Erros comuns e anti-patterns

As scope functions melhoram a legibilidade quando usadas com moderacao. Mas o abuso delas cria código mais difícil de ler do que o original.

**Nesting excessivo** — o erro mais comum:

```kotlin
// RUIM — difícil de ler
usuario?.let { u ->
    u.endereco?.let { e ->
        e.cidade?.let { c ->
            println("Cidade: $c")
        }
    }
}

// BOM — simples e direto
val cidade = usuario?.endereco?.cidade
if (cidade != null) {
    println("Cidade: $cidade")
}
```

**Usar scope function sem necessidade:**

```kotlin
// RUIM — let desnecessário
val tamanho = lista.let { it.size }

// BOM — direto
val tamanho = lista.size
```

**Misturar retornos:** tenha cuidado com `apply` e `run` dentro da mesma cadeia — os retornos diferentes podem causar bugs sutis.

A regra de ouro: se a scope function não torna o código mais claro, não use. Código explícito sempre vence código "esperto".

## Exemplos do mundo real

Para consolidar, veja como as scope functions aparecem em código de produção:

**Configuracao de cliente HTTP com apply:**

```kotlin
val client = OkHttpClient.Builder().apply {
    connectTimeout(30, TimeUnit.SECONDS)
    readTimeout(30, TimeUnit.SECONDS)
    addInterceptor(loggingInterceptor)
    if (BuildConfig.DEBUG) {
        addInterceptor(debugInterceptor)
    }
}.build()
```

**Processamento de resposta com let:**

```kotlin
fun buscarUsuario(id: Int): UsuarioDTO? {
    return repositorio.findById(id)?.let { entidade ->
        UsuarioDTO(
            nome = entidade.nome,
            email = entidade.email,
            ativo = entidade.deletadoEm == null
        )
    }
}
```

**Logging condicional com also:**

```kotlin
fun processarPagamento(pedido: Pedido): Resultado {
    return gateway.cobrar(pedido.valor)
        .also { resultado ->
            if (resultado.sucesso) {
                logger.info("Pagamento aprovado: ${pedido.id}")
            } else {
                logger.warn("Pagamento recusado: ${pedido.id} - ${resultado.motivo}")
            }
        }
}
```

## Conclusao

As scope functions sao ferramentas poderosas que, quando bem usadas, tornam o código Kotlin mais conciso e expressivo. A chave é entender as duas dimensões: como o objeto é referenciado (`this` vs `it`) e o que é retornado (resultado da lambda vs objeto contexto).

Com a prática, a escolha se torna intuitiva. Comece com `let` para [null-safety](/blog/null-safety-kotlin/), `apply` para configuracao de objetos e `also` para logging. Conforme ganhar confiança, incorpore `run` e `with` no seu repertório. E lembre-se: se o código fica mais confuso com scope function, é melhor sem ela.

Para aprofundar seus conhecimentos na linguagem, confira nosso guia sobre [o que é Kotlin](/blog/o-que-e-kotlin/) e o tutorial de [extension functions](/blog/extension-functions-kotlin/), que complementam perfeitamente o entendimento das scope functions. Se você programa em outras linguagens, é interessante comparar: <a href="https://rustlang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Rust não tem scope functions, mas resolve encadeamento com pattern matching e closures</a>, enquanto <a href="https://python.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'python.dev.br' })">Python usa context managers (with) para um propósito similar</a>.
