O que é fun em Kotlin?

A palavra-chave fun é usada para declarar funções em Kotlin. Toda função na linguagem começa com fun, seguida do nome, dos parâmetros entre parênteses e, opcionalmente, do tipo de retorno.

Se você está acostumado com Java, vai perceber que em Kotlin as funções são bem mais enxutas. Dá pra escrever bastante coisa com poucas linhas.

Sintaxe básica

fun saudacao(nome: String): String {
    return "Olá, $nome! Bem-vindo ao Kotlin Brasil."
}

fun main() {
    println(saudacao("Karina"))
}

Os parâmetros são declarados no formato nome: Tipo, e o tipo de retorno vem depois dos parênteses, separado por :. Se a função não retorna nada, o tipo de retorno é Unit — mas você não precisa escrever isso explicitamente.

Funções de expressão única

Quando a função tem só uma expressão, dá pra simplificar bastante usando o sinal de =:

fun dobro(x: Int): Int = x * 2

fun saudacao(nome: String) = "E aí, $nome! Tudo certo?"

Repare que na segunda função nem precisou declarar o tipo de retorno. O compilador infere sozinho que é String.

Parâmetros com valor padrão

Kotlin permite definir valores padrão nos parâmetros, o que é uma mão na roda:

fun criarUsuario(nome: String, ativo: Boolean = true): String {
    return "$nome - Ativo: $ativo"
}

fun main() {
    println(criarUsuario("Ana"))          // Ana - Ativo: true
    println(criarUsuario("João", false))  // João - Ativo: false
}

Isso elimina a necessidade de vários overloads que seriam obrigatórios em Java.

Funções são cidadãs de primeira classe

Em Kotlin, funções podem ser armazenadas em variáveis, passadas como argumento e retornadas por outras funções. Isso abre as portas para programação funcional de um jeito muito natural.

Argumentos nomeados

Uma funcionalidade poderosa do Kotlin é chamar funções usando o nome dos parâmetros. Isso melhora a legibilidade, especialmente em funções com muitos parâmetros:

fun criarPedido(
    produto: String,
    quantidade: Int,
    desconto: Double = 0.0,
    frete: Boolean = true
): String {
    return "$quantidade x $produto (desconto: $desconto, frete: $frete)"
}

fun main() {
    println(criarPedido(produto = "Teclado", quantidade = 2, frete = false))
    // 2 x Teclado (desconto: 0.0, frete: false)
}

Com argumentos nomeados, você pode pular parâmetros com valor padrão e chamar em qualquer ordem, tornando o código mais legível e menos propenso a erros.

Funções de extensão

Kotlin permite adicionar funções a classes existentes sem herança usando extension functions:

fun String.contarPalavras(): Int {
    return this.trim().split("\\s+".toRegex()).size
}

fun main() {
    val frase = "Kotlin e uma linguagem moderna"
    println(frase.contarPalavras()) // 5
}

A função contarPalavras se comporta como se fosse um método nativo da classe String, mas foi definida fora dela. Esse recurso é amplamente usado em bibliotecas Kotlin para estender APIs existentes de forma elegante.

Funções locais

Você pode declarar funções dentro de outras funções para encapsular lógica auxiliar:

fun processarPedido(itens: List<String>): String {
    fun validar(item: String): Boolean {
        return item.isNotBlank() && item.length <= 100
    }

    val validos = itens.filter { validar(it) }
    return "Processando ${validos.size} itens validos"
}

Funções locais têm acesso às variáveis da função externa, o que as torna práticas para lógica que só faz sentido naquele contexto.

Casos de Uso no Mundo Real

  • Endpoints de API REST: cada endpoint em frameworks como Ktor ou Spring é definido como uma função, aproveitando parâmetros com valor padrão para configurações opcionais como paginação e filtros.
  • Transformação de dados: funções de expressão única são ideais para mapear DTOs em entidades de domínio, mantendo o código de conversão conciso e fácil de localizar.
  • Validação de formulários: funções com parâmetros nomeados facilitam a criação de validadores reutilizáveis onde cada regra é configurável e legível.
  • Funções utilitárias em projetos Android: extension functions permitem adicionar métodos como View.esconder() ou String.formatarCPF() sem criar classes utilitárias estáticas.

Boas Práticas

  • Prefira funções de expressão única quando o corpo da função cabe em uma linha. Isso reduz ruído visual e torna o código mais direto.
  • Use parâmetros com valor padrão em vez de criar múltiplos overloads. O resultado é mais limpo e mais fácil de manter.
  • Nomeie funções com verbos que descrevam a ação: calcularTotal, buscarUsuario, validarEmail. Nomes claros dispensam comentários.
  • Mantenha funções curtas e com uma única responsabilidade. Se a função faz mais de uma coisa, divida em funções menores.
  • Declare o tipo de retorno explicitamente em funções públicas de APIs e bibliotecas, mesmo quando o compilador pode inferir, para melhorar a documentação do código.

Erros Comuns

  • Esquecer que parâmetros com valor padrão devem vir por último: ao misturar parâmetros obrigatórios e opcionais, coloque os opcionais no final. Caso contrário, será necessário usar argumentos nomeados em toda chamada.
  • Retornar Unit explicitamente quando não é necessário: funções que não retornam valor não precisam de return Unit nem de declarar : Unit. Basta omitir.
  • Criar extension functions com nomes que conflitam com métodos da classe: se a classe já tem um método com o mesmo nome e assinatura, o método da classe sempre tem prioridade, e a extension function nunca será chamada.
  • Não usar @JvmOverloads ao expor funções com valores padrão para código Java: sem essa anotação, o Java só enxerga a versão com todos os parâmetros, perdendo os benefícios dos defaults.
  • Declarar funções longas de expressão única: se a expressão é complexa ou ocupa múltiplas linhas, use a forma com corpo e return. A forma de expressão única deve ser reservada para lógica simples.

Perguntas Frequentes

Qual a diferença entre fun em Kotlin e def em Python? Ambas declaram funções, mas fun exige tipos explícitos para os parâmetros (inferência funciona apenas para o retorno em expressões únicas). Kotlin é estaticamente tipado, enquanto Python é dinamicamente tipado.

Posso criar funções fora de classes em Kotlin? Sim. Kotlin suporta funções de nível superior (top-level functions) que não pertencem a nenhuma classe. Elas são compiladas como métodos estáticos de uma classe gerada automaticamente.

O que acontece se eu declarar uma função sem tipo de retorno? Se você usa a forma com corpo (chaves), o tipo de retorno padrão é Unit. Se usa a forma de expressão única, o compilador infere o tipo a partir da expressão.

Posso sobrecarregar funções em Kotlin? Sim. Kotlin suporta sobrecarga (overload) de funções com o mesmo nome mas assinaturas diferentes. No entanto, parâmetros com valor padrão frequentemente eliminam a necessidade de overloads.

Termos Relacionados

  • Lambda — funções anônimas que complementam o uso de fun
  • Higher-Order Function — funções que recebem ou retornam outras funções declaradas com fun
  • Inline — modificador que otimiza funções que recebem lambdas
  • Interface — contratos que podem declarar funções abstratas implementadas com fun