Funções Anônimas em Golang

GolangBeginner
Pratique Agora

Introdução

Nos laboratórios anteriores, você aprendeu a escrever e usar funções nomeadas, como organizar código em módulos e como melhorar a legibilidade do código dividindo a lógica em funções separadas. Neste laboratório, exploraremos funções anônimas (anonymous functions), um tipo especial de função que não possui nome. Funções anônimas são úteis quando você deseja definir um pequeno trecho de lógica "no local" sem ter que declarar uma função nomeada separada. Elas são particularmente úteis para operações curtas e autocontidas, ou quando você precisa passar uma função como argumento para outra função (como em callbacks). Ao usar funções anônimas, você pode escrever um código mais conciso e expressivo.

Tópicos Chave:

  • O que são funções anônimas e como defini-las
  • Por que e quando usar funções anônimas
  • Chamando funções anônimas sem atribuí-las a um nome
  • Passando parâmetros para funções anônimas e retornando valores
  • Usando funções anônimas como funções callback para um código mais flexível

Entendendo Funções Anônimas

Uma função anônima em Go é definida da mesma forma que uma função normal, exceto que ela não possui um nome. Em vez disso, você pode atribuí-la a uma variável, passá-la como um argumento ou executá-la imediatamente após sua definição. Isso as torna adequadas para operações curtas e únicas, ou para passar funções como argumentos para outras funções. Funções anônimas são particularmente úteis quando uma função é necessária apenas uma vez e não justifica uma função nomeada separada. Elas podem ajudar a tornar seu código mais legível, mantendo a lógica próxima de onde ela é usada.

Sintaxe para uma função anônima:

func(input parameters)(return parameters) {
    // code block
}

Isso se assemelha à definição de uma função regular, mas sem o nome da função.

Comparando com uma declaração de função regular:

// Regular function declaration
func functionName(parameters...)(return values...) {
    code block
}

Por que usar funções anônimas?

  • Concisão: Elas permitem que você defina pequenos trechos de lógica sem ter que criar uma função nomeada separada, tornando o código mais conciso.
  • Escopo Local: O escopo das funções anônimas está dentro da função circundante, limitando assim a poluição do namespace.
  • Flexibilidade: Elas podem ser passadas como argumentos para outras funções ou definidas e executadas imediatamente.

Quando usar funções anônimas?

  • Quando você precisa de uma função curta que não será reutilizada em outro lugar.
  • Como funções callback (veremos isso mais tarde).
  • Quando você deseja executar uma função imediatamente (frequentemente para inicialização).

Criando uma Função Anônima sem Parâmetros

Vamos começar com um exemplo simples que imprime "hello world" usando uma função anônima. Primeiro, crie um arquivo chamado anonymous.go no diretório do projeto:

cd ~/project
touch anonymous.go

Abra anonymous.go e adicione o seguinte código:

package main

import "fmt"

func main() {
    // Define an anonymous function and assign it to a variable f
    f := func() {
        fmt.Println("hello world")
    }

    // Call the anonymous function via the variable f
    f()
}

Execute o programa:

go run anonymous.go

Saída esperada:

hello world

Aqui, definimos uma função anônima usando a sintaxe func() { ... }. Esta função não recebe nenhum parâmetro e não retorna nenhum valor. Atribuímos esta função anônima à variável f. Em seguida, chamamos a função usando f(). Isso executa a função anônima e imprime "hello world".

Usando Parâmetros em Funções Anônimas

Funções anônimas podem aceitar parâmetros, assim como funções regulares. Vamos modificar nosso código para passar uma string como um parâmetro.

Substitua o conteúdo de anonymous.go por:

package main

import "fmt"

func main() {
    f := func(s string) {
        fmt.Println(s)
    }
    f("hello world")
}

Execute o programa:

go run anonymous.go

Saída esperada:

hello world

Desta vez, nossa função anônima recebe um parâmetro string s. A parte func(s string) define que a função anônima recebe um parâmetro chamado s do tipo string. Quando chamamos f("hello world"), a string "hello world" é passada para a função, que então a imprime no console. Isso demonstra como você pode passar valores para funções anônimas para torná-las mais versáteis.

Retornando Valores de Funções Anônimas

Funções anônimas também podem retornar valores. Vamos criar uma função anônima que recebe dois inteiros como parâmetros e retorna sua soma.

Substitua o conteúdo de anonymous.go por:

package main

import "fmt"

func main() {
    f := func(a, b int) int {
        return a + b
    }
    result := f(3, 5)
    fmt.Println(result)
}

Execute o programa:

go run anonymous.go

Saída esperada:

8

Agora, a assinatura da função anônima é func(a, b int) int. Isso significa que ela recebe dois inteiros (a e b) como entrada e retorna um inteiro como saída. O corpo da função, return a + b, calcula e retorna sua soma. Quando chamamos f(3, 5), ela executa a função anônima com os argumentos 3 e 5, e o resultado 8 é retornado. Em seguida, armazenamos este resultado na variável result e o imprimimos no console.

Declarando e Chamando Funções Anônimas Imediatamente

Você pode definir e chamar uma função anônima de uma só vez, sem atribuí-la a uma variável. Isso pode ser útil para operações rápidas e únicas.

Atualize anonymous.go:

package main

import "fmt"

func main() {
    res := func(a, b int) int {
        return a + b
    }(3, 5) // Chame a função anônima diretamente aqui
    fmt.Println(res)
}

Execute o programa:

go run anonymous.go

Saída esperada:

8

Aqui, definimos a função anônima func(a, b int) int { return a + b } e a invocamos imediatamente adicionando (3, 5) após a declaração da função. Esta sintaxe func(...) {...}(...) permite que você defina e chame uma função em uma única expressão. Os argumentos dentro dos parênteses são passados para a função imediatamente. Neste caso, ela retorna a soma de 3 e 5, que é então atribuída à variável res. Esta é uma prática comum para funções simples e executadas imediatamente, e é útil para inicialização ou cálculos curtos.

Usando Funções Anônimas como Funções de Callback

Funções anônimas também podem ser usadas como callbacks (funções de retorno), o que significa que podemos passá-las como argumentos para outras funções. Isso é útil quando você deseja personalizar o comportamento de uma função sem criar uma função nomeada.

O que são Funções de Callback?

Uma função de callback é uma função que é passada como um argumento para outra função e é executada após a primeira função concluir sua tarefa. Isso permite que o chamador personalize o comportamento da função que está sendo chamada, proporcionando mais flexibilidade e modularidade. Em essência, a função que recebe um callback chamará a função de callback "de volta" em algum momento.

Por que usar Funções Anônimas como Callbacks?

Funções anônimas funcionam excepcionalmente bem como funções de callback porque frequentemente representam comportamentos curtos e específicos que são usados apenas dentro de um contexto particular. Usar uma função anônima como um callback mantém o código mais conciso e evita ter que definir uma função nomeada separada.

Substitua anonymous.go pelo seguinte código:

package main

import (
    "fmt"
    "math"
)

// 'visit' recebe uma fatia e uma função. Ela aplica a função a cada elemento na fatia.
func visit(lst []float64, f func(float64)) {
    for _, value := range lst {
        f(value)
    }
}

func main() {
    arr := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}

    // Use uma função anônima para somar cada elemento com ele mesmo
    visit(arr, func(v float64) {
        fmt.Printf("Sum:%.0f ", v+v)
    })
    fmt.Println()

    // Use uma função anônima para multiplicar cada elemento por ele mesmo
    visit(arr, func(v float64) {
        fmt.Printf("Product:%.0f ", v*v)
    })
    fmt.Println()

    // Use uma função anônima para elevar ao quadrado cada elemento usando math.Pow
    visit(arr, func(v float64) {
        v = math.Pow(v, 2)
        fmt.Printf("Square:%.0f ", v)
    })
    fmt.Println()
}

Execute o programa:

go run anonymous.go

Saída esperada:

Sum:2 Sum:4 Sum:6 Sum:8 Sum:10 Sum:12 Sum:14 Sum:16 Sum:18
Product:1 Product:4 Product:9 Product:16 Product:25 Product:36 Product:49 Product:64 Product:81
Square:1 Square:4 Square:9 Square:16 Square:25 Square:36 Square:49 Square:64 Square:81

Neste programa, primeiro criamos uma função visit que recebe uma fatia (lst) de float64 e uma função (f) do tipo func(float64). A função visit itera sobre a fatia e chama a função fornecida f para cada elemento. Este padrão de projeto permite que a função visit execute diferentes lógicas dependendo da função de callback f fornecida.

Dentro da função main, chamamos visit três vezes com diferentes funções anônimas para demonstrar como os callbacks fornecem flexibilidade.

  • A primeira função anônima calcula a soma de cada elemento com ele mesmo.
  • A segunda função anônima calcula o produto de cada elemento com ele mesmo.
  • A terceira função anônima eleva ao quadrado cada elemento usando math.Pow.

Isso ilustra como uma função anônima pode ser passada como um callback e como a função visit pode realizar diferentes ações com base na função de callback passada como um parâmetro. Isso torna seu código mais reutilizável e modular.

Resumo

Neste laboratório, você aprendeu sobre funções anônimas em Go. Funções anônimas não têm nome e são frequentemente usadas para trechos curtos e descartáveis de lógica. Elas podem:

  • Ser atribuídas a variáveis e chamadas posteriormente.
  • Receber parâmetros e retornar valores.
  • Ser definidas e chamadas imediatamente.
  • Servir como callbacks quando passadas como argumentos para outras funções, permitindo um comportamento altamente flexível e personalizável.

Funções anônimas oferecem flexibilidade e conveniência, especialmente quando você precisa de lógica personalizada "on the fly" (na hora) sem sobrecarregar sua base de código com muitas funções nomeadas. Ao usá-las efetivamente, você pode criar programas Go mais expressivos, concisos e modulares. Elas são uma ferramenta poderosa para escrever código mais limpo, legível e flexível.