Introdução
Uma função é uma seção do código que, uma vez definida, pode ser reutilizada. As funções são usadas para deixar seu código mais fácil de entender: o código é dividido em tarefas menores e compreensíveis, que podem ser usadas mais de uma vez ao longo do programa.
O Go vem com uma biblioteca padrão poderosa que possui várias funções predefinidas. As funções do pacote fmt, com as quais provavelmente você já está familiarizado, são:
fmt.Println()
– que imprimirá objetos para a saída padrão (provavelmente o seu terminal).fmt.Printf()
– que permite que você formate seu resultado impresso.
Os nomes das funções incluem parênteses e podem incluir parâmetros.
Neste tutorial, vamos explicaremos sobre como definir suas próprias funções para usar em seus projetos de código.
Definindo uma função
Vamos começar a transformar o programa clássico “Hello, World!” em uma função.
Criaremos um novo arquivo de texto em nosso editor de textos preferido e chamaremos o programa hello.go
. Então, vamos definir a função.
Uma função é definida usando a palavra-chave func
. Depois dessa palavra-chave vem um nome de sua escolha e um conjunto de parênteses que possui quaisquer parâmetros que a função receberá (elas podem ficar vazias). As linhas de código da função ficam entre chaves {}
.
Neste caso, vamos definir uma função chamada hello()
:
hello.go
func hello() {}
Isso define a instrução inicial para a criação de uma função.
A partir daqui, adicionaremos uma segunda linha para fornecer as instruções para o que a função faz. Neste caso, vamos imprimir Hello, World!
para o console:
hello.go
func hello() {
fmt.Println("Hello, World!")
}
Nossa função agora está totalmente definida; porém, se executarmos o programa neste ponto, nada acontecerá, pois não chamamos a função.
Assim, dentro do nosso bloco de funções main()
, vamos chamar a função com hello()
:
hello.go
package main
import "fmt"
func main() {
hello()
}
func hello() {
fmt.Println("Hello, World!")
}
Agora, vamos executar o programa:
Você receberá o seguinte resultado:
Output
Hello, World!
Note que também introduzimos uma função chamada main()
. A função main()
é uma função especial que diz ao compilador que é aqui que o programa deve iniciar. Para qualquer programa que você queira que seja executável (um programa que pode ser executado a partir da linha de comando), você vai precisar de uma função main()
. A função main()
deve aparecer apenas uma vez, estar no pacote main()
e não deve receber nem retornar argumentos. Isso permite a execução do programa em qualquer programa em Go. De acordo com o exemplo a seguir:
main.go
package main
import "fmt"
func main() {
fmt.Println("this is the main section of the program")
}
As funções podem ficar mais complicadas do que a função hello()
que definimos. Podemos usar loops for
, instruções condicionais e mais, dentro do nosso bloco de função.
Por exemplo, a função a seguir usa uma instrução condicional para verificar se a entrada da variável name
contém uma vogal; depois, ela usa um loop for
para iterar nas letras da string name
.
names.go
package main
import (
"fmt"
"strings"
)
func main() {
names()
}
func names() {
fmt.Println("Enter your name:")
var name string
fmt.Scanln(&name)
// Check whether name has a vowel
for _, v := range strings.ToLower(name) {
if v == 'a' || v == 'e' || v == 'i' || v == 'o' || v == 'u' {
fmt.Println("Your name contains a vowel.")
return
}
}
fmt.Println("Your name does not contain a vowel.")
}
A função name()
que definimos aqui define uma variável name
com entrada e, em seguida, define uma instrução condicional dentro de um loop for
. Isso mostra como o código pode ser organizado dentro de uma definição de função. No entanto, dependendo do que pretendemos com nosso programa e como queremos configurar nosso código, podemos querer definir a instrução condicional e o loop for
como duas funções separadas.
Definir funções dentro de um programa torna o nosso código modular e reutilizável para que possamos chamar as mesmas funções sem reescrevê-las.
Até agora, examinamos funções com parênteses vazios, que não recebem argumentos, mas podemos definir parâmetros nas definições da função dentro de seus parênteses.
Um parâmetro é uma entidade nomeada na definição de uma função, que especifica um argumento que a função pode aceitar. Na linguagem Go, você deve especificar o tipo de dados de cada parâmetro.
Vamos criar um programa que repete uma palavra pelo número de vezes especificado. O programa aceitará um parâmetro de string
, chamado word
e um parâmetro de int
chamado reps
em relação ao número de vezes a se repetir a palavra.
repeat.go
package main
import "fmt"
func main() {
repeat("Sammy", 5)
}
func repeat(word string, reps int) {
for i := 0; i < reps; i++ {
fmt.Print(word)
}
}
Enviamos o valor Sammy
para o parâmetro word
e 5
para o parâmetro reps
. Esses valores correspondem a cada parâmetro na ordem que eles foram dados. A função repeat
tem um loop for
que irá iterar pelo número de vezes especificado pelo parâmetro reps
. Para cada iteração, o valor do parâmetro word
será impresso.
Aqui está o resultado do programa:
Output
SammySammySammySammySammy
Se você tiver um conjunto de parâmetros - todos com o mesmo valor, você pode omitir, especificando o tipo a cada vez. Vamos criar um pequeno programa que recebe os parâmetros x
, y
e z
que estão todos com valores int
. Criaremos uma função que adiciona os parâmetros juntos, em configurações diferentes. As somas deles serão impressos pela função. Então, vamos chamar a função e enviar números para a função.
add_numbers.go
package main
import "fmt"
func main() {
addNumbers(1, 2, 3)
}
func addNumbers(x, y, z int) {
a := x + y
b := x + z
c := y + z
fmt.Println(a, b, c)
}
Ao criarmos a assinatura da função para addNumbers
, não precisamos especificar o tipo a cada vez, apenas no final.
Enviamos o número 1
para o parâmetro x
, o 2
para o parâmetro y
e o 3
para o parâmetro z
. Esses valores correspondem a cada parâmetro na ordem em que eles são dados.
O programa está fazendo a seguinte operação matemática, com base nos valores que enviamos para os parâmetros:
a = 1 + 2
b = 1 + 3
c = 2 + 3
A função também imprime a
, b
e c
e, com base nessa operação matemática, esperamos que a seja igual a
3
, b
igual a 4
e c
igual a 5
. Vamos executar o programa:
Output
3 4 5
Quando enviamos 1
, 2
e 3
como parâmetros para a função addNumbers()
, recebemos o resultado esperado.
Os parâmetros são argumentos, normalmente definidos como variáveis nas definições da função. Ao executar o método, você pode atribuir valores aos parâmetros, enviando os argumentos para a função.
Retornando um valor
Você pode enviar um valor de parâmetro para uma função e uma função também pode produzir um valor.
Uma função pode produzir um valor com a instrução return
, o qual sairá de uma função e enviará, opcionalmente, uma expressão de volta para o chamador. O tipo de dados retornados também deve ser especificado.
Até agora, usamos a instrução fmt.Println()
em vez da instrução return
em nossas funções. Vamos criar um programa que, em vez de imprimir, retornará uma variável.
Em um novo arquivo de texto chamado double.go
, vamos criar um programa que duplica o parâmetro x
e retorna a variável y
. Nós emitimos uma chamada para imprimir a variável result
, que é formada por meio da execução da função double()
com um 3
enviado para ela:
double.go
package main
import "fmt"
func main() {
result := double(3)
fmt.Println(result)
}
func double(x int) int {
y := x * 2
return y
}
Podemos executar o programa e ver o resultado:
Output
6
O número inteiro 6
é retornado como o resultado, que se trata do que esperávamos da multiplicação de 3
por 2
.
Se uma função especifica um retorno, você deve fornecer um retorno como parte do código. Se não fizer isso, receberá um erro de compilação.
Podemos demonstrar isso, comentando a linha (do código) com a instrução de retorno:
double.go
package main
import "fmt"
func main() {
result := double(3)
fmt.Println(result)
}
func double(x int) int {
y := x * 2
// return y
}
Agora, vamos executar o programa novamente:
Output
./double.go:13:1: missing return at end of function
Sem usar a instrução return
aqui, o programa não pode compilar.
As funções saem imediatamente quando atingem a instrução return
, mesmo se elas não estiverem no final da função:
return_loop.go
package main
import "fmt"
func main() {
loopFive()
}
func loopFive() {
for i := 0; i < 25; i++ {
fmt.Print(i)
if i == 5 {
// Stop function at i == 5
return
}
}
fmt.Println("This line will not execute.")
}
Aqui, iteramos um loop for
e dizemos ao loop para executar 25
iterações. No entanto, dentro do loop for
, temos uma instrução condicional if
que verifica se o valor de i
é igual a 5
. Se for, emitimos uma instrução return
. Como estamos na função loopFive
, qualquer return
em qualquer ponto na função sairá da função. Consequentemente, nunca chegaremos à última linha dessa função para imprimir a instrução This line will not execute.
(Esta linha não será executada.).
Usar a instrução return
dentro do loop for
encerra a função, de modo que a linha que está fora do loop não será executada. Se, em vez disso, tivéssemos usado uma instrução break
, apenas o loop teria saído naquele momento e a última linha da fmt.Println()
seria executada.
A instrução return
sai de uma função e pode retornar um valor se especificado na assinatura da função.
Retornando valores múltiplos
Mais de um valor retornado pode ser especificado para uma função. Vamos examinar o programa repeat.go
e fazer com que ele retorne dois valores. O primeiro será o valor repetido e o segundo será um erro se o parâmetro reps
não for um valor maior que 0
:
repeat.go
package main
import "fmt"
func main() {
val, err := repeat("Sammy", -1)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(val)
}
func repeat(word string, reps int) (string, error) {
if reps <= 0 {
return "", fmt.Errorf("invalid value of %d provided for reps. value must be greater than 0.", reps)
}
var value string
for i := 0; i < reps; i++ {
value = value + word
}
return value, nil
}
A primeira coisa que a função repeat
faz é verificar se o argumento reps
é um valor válido. Qualquer valor que não seja maior do que 0
causará um erro. Como enviamos o valor de -1
, essa ramificação do código será executada. Note que, quando retornamos da função, precisamos fornecer os valores retornados string
e error
. Como os argumentos fornecidos resultaram em um erro, vamos enviar uma string em branco de volta para o primeiro valor retornado e o erro para o segundo valor retornado.
Na função main()
podemos receber ambos valores retornados, declarando duas novas variáveis, value
e err
. Como pode haver um erro no retorno, vamos verificar se recebemos um erro antes de continuar com nosso programa. Neste exemplo, recebemos um erro. Nós imprimimos o erro e o return
da função main()
para sair do programa.
Se não houvesse um erro, imprimiríamos o valor retornado da função.
Nota: é considerada uma melhor prática retornar apenas dois ou três valores. Além disso, você deve sempre retornar todos os erros como o último valor de retorno de uma função.
Executar o programa resultará no seguinte resultado:
Output
invalid value of -1 provided for reps. value must be greater than 0.
Nesta seção, analisamos como podemos usar a instrução return
para retornar valores múltiplos de uma função.
Conclusão
As funções são blocos de código de instruções que realizam ações dentro de um programa, ajudando a tornar o nosso código reutilizável e modular.
Para aprender mais sobre como tornar seu código mais modular, leia o nosso guia sobre Como escrever pacotes em Go.