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:
- go run hello.go
Você receberá o seguinte resultado:
OutputHello, 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.
Trabalhando com parâmetros
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:
OutputSammySammySammySammySammy
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:
- go run add_numbers.go
Output3 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:
- go run double.go
Output6
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:
- go run double.go
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:
Outputinvalid 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.