Funções
Esta aula ensina a declarar e usar funções em Go, cobrindo múltiplos retornos, parâmetros variádicos e funções com retorno nomeado. Você verá exemplos práticos e exercícios para fixar os conceitos.
Funções são blocos de código reutilizáveis que executam uma tarefa específica. Em Go, as funções são cidadãs de primeira classe, podendo ser atribuídas a variáveis, passadas como argumentos e retornadas de outras funções. Nesta aula, você aprenderá a declarar funções, trabalhar com múltiplos retornos, usar parâmetros variádicos e explorar as funções com retorno nomeado, um recurso que torna o código mais expressivo.
Go adota uma sintaxe concisa e clara para funções, com tipos declarados após os nomes dos parâmetros. A linguagem também oferece suporte nativo a múltiplos valores de retorno, o que é útil para retornar resultados e erros simultaneamente. Vamos mergulhar em cada tópico com exemplos práticos.
Declaração
Em Go, a declaração de uma função começa com a palavra-chave func, seguida pelo nome, parâmetros entre parênteses e o tipo de retorno (se houver). O corpo da função é delimitado por chaves. A sintaxe básica é:
func nome(parametros) tipo_retorno {
// corpo
}Parâmetros são especificados com nome e tipo, separados por vírgula. Se dois ou mais parâmetros consecutivos têm o mesmo tipo, o tipo pode ser declarado apenas no último. Funções que não retornam valor não precisam de tipo de retorno. Exemplo:
package main
import "fmt"
// Função que não retorna valor
func saudacao(nome string) {
fmt.Printf("Olá, %s!\n", nome)
}
// Função que retorna um inteiro
func soma(a, b int) int {
return a + b
}
func main() {
saudacao("Maria")
resultado := soma(3, 4)
fmt.Println("Soma:", resultado)
}Observe que a função soma declara a, b int sem repetir o tipo. A chamada saudacao("Maria") executa a função, e soma(3, 4) retorna um valor que é armazenado na variável resultado.
Múltiplos retornos
Go permite que uma função retorne múltiplos valores. Isso é comum para retornar um resultado e um erro, ou vários resultados de uma operação. Os tipos de retorno são listados entre parênteses, separados por vírgula. Exemplo:
package main
import "fmt"
// Retorna dois inteiros
func divisao(dividendo, divisor int) (int, int) {
quociente := dividendo / divisor
resto := dividendo % divisor
return quociente, resto
}
func main() {
q, r := divisao(10, 3)
fmt.Printf("Quociente: %d, Resto: %d\n", q, r)
}Na chamada, os valores retornados são atribuídos a múltiplas variáveis na ordem correspondente. Se você não precisar de um dos retornos, use o identificador em branco _:
q, _ := divisao(10, 3) // ignora o resto
fmt.Println("Quociente:", q)Múltiplos retornos são frequentemente usados para propagar erros. Por convenção, o erro é o último valor retornado:
func dividir(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("divisão por zero")
}
return a / b, nil
}
func main() {
resultado, err := dividir(10, 0)
if err != nil {
fmt.Println("Erro:", err)
} else {
fmt.Println("Resultado:", resultado)
}
}Parâmetros variádicos
Parâmetros variádicos permitem que uma função receba um número variável de argumentos. Em Go, isso é feito usando ... antes do tipo do último parâmetro. Dentro da função, o parâmetro variádico se comporta como um slice. Exemplo:
package main
import "fmt"
func media(numeros ...float64) float64 {
total := 0.0
for _, n := range numeros {
total += n
}
return total / float64(len(numeros))
}
func main() {
fmt.Println("Média:", media(10, 20, 30)) // 20
fmt.Println("Média:", media(5.5, 6.5, 7.5, 8.5)) // 7.0
}Você também pode passar um slice para uma função variádica usando a sintaxe slice...:
nums := []float64{1, 2, 3, 4}
fmt.Println("Média:", media(nums...))Importante: o parâmetro variádico deve ser o último parâmetro. Não é permitido ter mais de um parâmetro variádico.
Funções nomeadas de retorno
Go permite nomear os valores de retorno de uma função. Isso pode tornar o código mais legível, especialmente quando há múltiplos retornos. Os nomes atuam como variáveis declaradas no início da função, e um return sem argumentos retorna os valores atuais dessas variáveis (chamado de bare return). Exemplo:
package main
import "fmt"
func calcular(a, b int) (soma int, produto int) {
soma = a + b
produto = a * b
return // retorna soma e produto automaticamente
}
func main() {
s, p := calcular(4, 5)
fmt.Println("Soma:", s, "Produto:", p)
}Os nomes soma e produto são inicializados com zero (valores zero de int). Dentro da função, você atribui valores a eles e, ao final, um return sem argumentos os retorna. Embora seja conveniente, o uso de bare return pode prejudicar a legibilidade em funções longas; é recomendado apenas em funções curtas.
Você também pode misturar retornos nomeados com retornos explícitos, mas evite confusão. Prefira sempre retornar explicitamente os valores, a menos que a função seja muito simples.
Boas práticas
- Prefira funções curtas e focadas em uma única tarefa.
- Use nomes descritivos para parâmetros e retornos.
- Ao retornar erros, sempre retorne o erro como o último valor.
- Evite bare return em funções com mais de 10 linhas.
- Documente funções exportadas com comentários iniciando pelo nome da função.
Referências
- Effective Go - Functions
- Go Specification - Function declarations
- Go Specification - Function types
- Go Specification - Multiple return values
- Go Specification - Variadic parameters
- Go Specification - Return statements
Exercícios
Crie uma função chamada
maiorque recebe dois inteiros e retorna o maior deles. Teste com os valores 10 e 20.✓ Resposta:func maior(a, b int) int { if a > b { return a } return b } func main() { fmt.Println(maior(10, 20)) // 20 }Escreva uma função chamada
trocarque recebe dois inteiros e retorna os mesmos valores em ordem inversa (primeiro retorna o segundo, e vice-versa). Teste com (1, 2).✓ Resposta:func trocar(a, b int) (int, int) { return b, a } func main() { x, y := trocar(1, 2) fmt.Println(x, y) // 2 1 }Crie uma função variádica chamada
concatenarque recebe strings e as concatena com um espaço entre elas. Teste com "Go", "é", "legal".✓ Resposta:func concatenar(palavras ...string) string { return strings.Join(palavras, " ") } func main() { fmt.Println(concatenar("Go", "é", "legal")) // "Go é legal" }Escreva uma função com retornos nomeados chamada
dividirque recebe dois inteiros e retorna quociente e resto (nomes:quoerem). Use bare return. Teste com 10 e 3.✓ Resposta:func dividir(a, b int) (quo, rem int) { quo = a / b rem = a % b return } func main() { q, r := dividir(10, 3) fmt.Println(q, r) // 3 1 }Crie uma função que recebe um slice de inteiros e retorna a soma e a média (como float64). Use múltiplos retornos. Teste com []int{1,2,3,4,5}.
✓ Resposta:func somaMedia(numeros []int) (int, float64) { soma := 0 for _, n := range numeros { soma += n } media := float64(soma) / float64(len(numeros)) return soma, media } func main() { s, m := somaMedia([]int{1, 2, 3, 4, 5}) fmt.Println("Soma:", s, "Média:", m) // Soma: 15 Média: 3 }