---
title: "Crossinline em Kotlin: O que É e Como Funciona | Kotlin Brasil"
url: "https://kotlin.dev.br/glossario/crossinline/"
markdown_url: "https://kotlin.dev.br/glossario/crossinline.MD"
description: "Entenda o que é crossinline em Kotlin, como impedir non-local returns em lambdas inline executadas em outro contexto."
date: "2025-08-05"
author: "Karina Melo"
---

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

Entenda o que é crossinline em Kotlin, como impedir non-local returns em lambdas inline executadas em outro contexto.


## O que é crossinline em Kotlin?

O modificador **`crossinline`** é usado em parametros lambda de funções `inline` para indicar que a lambda **não pode usar non-local return**. Ele e necessário quando a lambda inlineada sera executada em um contexto diferente do fluxo normal da função, como dentro de outra lambda, um objeto anonimo ou uma coroutine.

Para entender `crossinline`, você primeiro precisa entender o que acontece com lambdas em funções `inline` é o conceito de non-local return.

### Non-local return: o contexto

Quando uma função e marcada como `inline`, as lambdas passadas a ela podem usar `return` para sair da função chamadora (non-local return):

```kotlin
inline fun executar(bloco: () -> Unit) {
    bloco()
}

fun main() {
    executar {
        println("Antes do return")
        return // Non-local return: sai de main()
    }
    println("Isso nunca e impresso")
}
```

Esse `return` sai de `main()`, não apenas da lambda. Isso e possível porque o compilador copia o corpo da lambda diretamente no local da chamada.

### O problema que crossinline resolve

O non-local return só funciona quando a lambda e executada diretamente no fluxo da função inline. Se a lambda for passada para outro contexto (como um Runnable ou uma coroutine), o non-local return não faz sentido e pode causar comportamento indefinido:

```kotlin
// Isso NAO compila sem crossinline
inline fun executarEmThread(bloco: () -> Unit) {
    val runnable = Runnable {
        bloco() // A lambda e executada em outro contexto!
    }
    Thread(runnable).start()
}
```

O compilador reclama porque `bloco` pode conter um `return` que tentaria sair da função chamadora, mas a lambda esta sendo executada em outra thread. A solução e `crossinline`:

```kotlin
inline fun executarEmThread(crossinline bloco: () -> Unit) {
    val runnable = Runnable {
        bloco() // Agora ok: crossinline impede non-local return
    }
    Thread(runnable).start()
}

fun main() {
    executarEmThread {
        println("Executando em outra thread")
        // return // Erro de compilacao! crossinline impede isso
    }
}
```

### Como funciona internamente

Com `crossinline`, o compilador ainda faz o inline do corpo da lambda (copiando o código), mas impede que `return` sem label seja usado. Você ainda pode usar `return@executarEmThread` (local return):

```kotlin
inline fun processar(crossinline bloco: () -> Unit) {
    val wrapper = object : Runnable {
        override fun run() {
            bloco()
        }
    }
    wrapper.run()
}

fun main() {
    processar {
        println("Processando...")
        return@processar // Local return: permitido
        // return // Non-local return: proibido pelo crossinline
    }
    println("Continua executando")
}
```

### Exemplo prático: builder com callback

Um caso real onde `crossinline` e necessário e quando você cria builders que armazenam lambdas para execução posterior:

```kotlin
class EventoBuilder {
    private val acoes = mutableListOf<() -> Unit>()

    fun adicionarAcao(acao: () -> Unit) {
        acoes.add(acao)
    }

    fun executar() {
        acoes.forEach { it() }
    }
}

inline fun construirEvento(crossinline configuracao: EventoBuilder.() -> Unit): EventoBuilder {
    val builder = EventoBuilder()
    builder.configuracao()
    return builder
}

fun main() {
    val evento = construirEvento {
        adicionarAcao { println("Acao 1") }
        adicionarAcao { println("Acao 2") }
    }
    evento.executar()
}
```

Sem `crossinline`, se `configuração` contivesse um `return`, ele tentaria sair da função chamadora de `construirEvento`, o que não faz sentido quando o builder sera usado depois.

### crossinline vs noinline

Ambos lidam com restricoes em lambdas de funções inline, mas de formas diferentes:

```kotlin
inline fun exemplo(
    crossinline lambdaCross: () -> Unit,  // Inlineada, sem non-local return
    noinline lambdaNo: () -> Unit          // NAO inlineada, tratada como objeto
) {
    val runnable1 = Runnable { lambdaCross() } // OK
    val runnable2 = Runnable { lambdaNo() }    // OK

    // lambdaNo pode ser armazenada em variavel
    val referência: () -> Unit = lambdaNo  // OK
    // val ref2: () -> Unit = lambdaCross  // Erro! crossinline ainda e inlineada
}
```

A diferenca chave:
- **`crossinline`**: a lambda ainda e inlineada (código copiado), mas sem non-local return. Nao pode ser armazenada como referência.
- **`noinline`**: a lambda não e inlineada, e tratada como um objeto Function normal. Pode ser armazenada, passada como parametro, etc.

### Quando usar crossinline

Use `crossinline` quando:

- A função e `inline` e a lambda sera passada para **outro contexto de execução** (thread, coroutine, objeto anonimo).
- Você quer manter os **beneficios de performance do inline** (sem alocacao de objeto Function) mas precisa impedir non-local return.
- A lambda sera executada dentro de outra lambda não-inline ou callback.

Na prática, o compilador vai te avisar quando `crossinline` e necessário. Se você tentar usar uma lambda inline em um contexto onde non-local return seria problematico, o compilador emite um erro sugerindo adicionar `crossinline`.

### Casos de Uso no Mundo Real

1. **Frameworks de injecao de dependência**: bibliotecas como Koin usam funções inline com lambdas de configuração que sao armazenadas internamente. O `crossinline` garante que o código do usuário não tente fazer non-local return de dentro do builder de modulos, mantendo a integridade do ciclo de vida do framework.

2. **DSLs de construcao de UI**: em frameworks como Jetpack Compose e bibliotecas de UI customizadas, lambdas de composicao sao passadas para contextos internos de renderizacao. O `crossinline` permite que essas lambdas sejam inlineadas para performance, sem permitir que um `return` interrompa o pipeline de renderizacao.

3. **Wrappers de execução assíncrona**: ao criar funções utilitarias que encapsulam o lancamento de coroutines ou execução em threads separadas, o `crossinline` e essencial para impedir que a lambda tente retornar da função chamadora quando esta sendo executada em outro contexto de thread.

4. **Sistemas de eventos e callbacks**: em arquiteturas orientadas a eventos, lambdas sao frequentemente registradas para execução futura. funções inline que registram esses handlers precisam de `crossinline` para manter os beneficios de performance do inline sem permitir non-local returns que não fariam sentido no momento da execução do evento.

### Boas Praticas

- Prefira `crossinline` em vez de `noinline` quando o único problema e o non-local return. Assim você mantém a otimização de inline (sem alocacao de objeto Function) e apenas restringe o tipo de return permitido.
- Deixe o compilador guiar você: na maioria dos casos, o compilador emitira um erro claro indicando que `crossinline` e necessário. Nao adicione o modificador preventivamente sem necessidade.
- Documente o motivo do `crossinline` na função com um comentario breve, especialmente em APIs publicas, para que outros desenvolvedores entendam por que a lambda não suporta non-local return.
- Ao projetar APIs inline com múltiplas lambdas, avalie cada parametro individualmente. Nem todas as lambdas precisam de `crossinline`; aplique apenas naquelas que serao executadas em outro contexto.
- Combine `crossinline` com contratos (`contract`) quando possível para preservar a capacidade do compilador de fazer smart casts mesmo com a restricao de return.

### Perguntas Frequentes

**P: Qual a diferenca entre crossinline e noinline na prática?**
R: O `crossinline` mantém o inline da lambda (o código e copiado no local da chamada, sem alocacao de objeto), mas impede non-local return. Ja o `noinline` faz com que a lambda seja tratada como um objeto Function normal, permitindo que seja armazenada em variaveis ou passada como argumento, porem sem os beneficios de performance do inline.

**P: O crossinline afeta a performance do código gerado?**
R: Nao negativamente. O `crossinline` mantém todos os beneficios de performance do inline. A única diferenca em relacao a uma lambda inline normal e a restricao de compilação que impede non-local return. O bytecode gerado e praticamente identico.

**P: Posso usar return com label dentro de uma lambda crossinline?**
R: Sim. O `crossinline` proibe apenas o non-local return (o `return` sem label que sairia da função chamadora). Voce ainda pode usar `return@nomeDaFuncao` para fazer um local return, que encerra apenas a execução da lambda.

**P: O compilador sempre avisa quando preciso usar crossinline?**
R: Sim, o compilador Kotlin detecta quando uma lambda inline e passada para um contexto onde non-local return seria inválido e emite um erro de compilação. A mensagem geralmente sugere adicionar `crossinline` ou `noinline` ao parametro.

### Erros comuns

1. **Tentar usar return sem label em lambda crossinline**: o compilador impede, mas iniciantes podem não entender o motivo do erro. Lembre-se de que `crossinline` proibe non-local return.

2. **Confundir crossinline com noinline**: usar `noinline` quando `crossinline` seria suficiente desperdiça a otimização do inline. Se você só precisa impedir non-local return, use `crossinline`.

3. **Usar crossinline desnecessariamente**: se a lambda e executada diretamente no fluxo da função inline, `crossinline` não e necessário e restringe sem motivo.

4. **Nao entender quando o compilador exige crossinline**: o erro do compilador pode parecer confuso. Sempre que você vir "can't inline ... into ...", considere adicionar `crossinline` ou `noinline`.

5. **Esquecer que crossinline não elimina o inline**: a lambda ainda e copiada no local da chamada. Apenas o non-local return e impedido.

### Exemplo com coroutines

Um cenário moderno onde `crossinline` aparece e em funções que lancam coroutines:

```kotlin
inline fun executarAsync(
    scope: CoroutineScope,
    crossinline bloco: suspend () -> Unit
) {
    scope.launch {
        bloco() // Executada em contexto de coroutine
    }
}
```

Sem `crossinline`, a lambda poderia tentar fazer non-local return da coroutine, o que não e válido.

### Termos relacionados

- **inline**: modificador que instrui o compilador a copiar o corpo da função no local da chamada.
- **noinline**: impede o inline de uma lambda específica, permitindo que seja tratada como objeto.
- **Non-local return**: capacidade de lambdas inline de retornar da função chamadora.
- **Lambda**: expressao funcional que pode ser passada como argumento, base do mecanismo de callbacks em Kotlin.
- **Higher-Order Function**: função que recebe ou retorna outra função.
- **Coroutine**: contexto assíncrono onde crossinline e frequentemente necessário.

O `crossinline` e um daqueles recursos que você não usa todos os dias, mas quando precisa, e essencial. Ele permite que funções inline aproveitem a otimização de performance sem os riscos de non-local returns em contextos onde isso seria perigoso. O compilador do Kotlin e inteligente o suficiente para te avisar quando precisa dele.
