One place for hosting & domains

      funções

      Como definir e chamar funções em Go


      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.



      Source link

      Como usar funções variadic em Go


      Introdução

      Uma função variadic é uma função que aceita zero, um, ou mais valores como um único argumento. Embora as funções variadic não sejam o caso comum, elas podem ser usadas para tornar seu código mais limpo e mais legível.

      As funções variadic são mais comuns do que parecem. A função mais comum é a Println do pacote fmt.

      func Println(a ...interface{}) (n int, err error)
      

      Uma função com um parâmetro antecedido por um sinal de reticências (...) é considerado como uma função variadic. As reticências significam que o parâmetro fornecido pode ser zero, um, ou mais valores. Para o pacote fmt.Println, elas declaram que o parâmetro a é uma função variadic.

      Vamos criar um programa que usa a função fmt.Println e envia valores zero, um ou mais:

      print.go

      package main
      
      import "fmt"
      
      func main() {
          fmt.Println()
          fmt.Println("one")
          fmt.Println("one", "two")
          fmt.Println("one", "two", "three")
      }
      

      A primeira vez que chamamos fmt.Println, não enviamos nenhum argumento. A segunda vez que chamamos fmt.Println, enviamos um único argumento apenas, com o valor de one. Então, enviamos one e two e, finalmente, one, two e three.

      Vamos executar o programa com o seguinte comando:

      Veremos o seguinte resultado:

      Output

      one one two one two three

      A primeira linha do resultado está em branco. Isso se deve ao fato de que não enviamos nenhum argumento na primeira vez que o fmt.Println foi chamado. Na segunda vez que chamamos a função, o valor one foi impresso. Em seguida, one e two e, finalmente, one, two e three.

      Agora que vimos como chamar uma função variadic, vamos examinar como podemos definir nossa própria função variadic.

      Definindo uma função variadic

      Podemos definir uma função variadic usando reticências (...) na frente do argumento. Vamos criar um programa que cumprimenta as pessoas quando seus nomes são enviados para a função:

      hello.go

      package main
      
      import "fmt"
      
      func main() {
          sayHello()
          sayHello("Sammy")
          sayHello("Sammy", "Jessica", "Drew", "Jamie")
      }
      
      func sayHello(names ...string) {
          for _, n := range names {
              fmt.Printf("Hello %sn", n)
          }
      }
      

      Criamos uma função sayHello que usa um único parâmetro chamado names. O parâmetro é variadic, uma vez que colocamos reticências (...) antes do tipo de dados: ...string. Isso diz ao Go que a função pode aceitar zero, um, ou muitos argumentos.

      A função sayHello recebe o parâmetro names como uma slice. Como o tipo de dados é uma string, o parâmetro names pode ser tratado como uma fatia de strings ([]string) dentro do corpo da função. Podemos criar um loop com o operador range e iterar ao longo da fatia de strings.

      Se executarmos o programa, vamos receber o seguinte resultado:

      Output

      Hello Sammy Hello Sammy Hello Jessica Hello Drew Hello Jamie

      Note que nada foi impresso na primeira vez que chamamos o sayHello. Isso acontece porque o parâmetro variadic era uma slice vazia da string. Como estamos formando loops pela fatia, não há nada para iterar até o fim e, dessa forma a função fmt.Printf nunca é chamada.

      Vamos modificar o programa para detectar se nenhum valor foi enviado:

      hello.go

      package main
      
      import "fmt"
      
      func main() {
          sayHello()
          sayHello("Sammy")
          sayHello("Sammy", "Jessica", "Drew", "Jamie")
      }
      
      func sayHello(names ...string) {
          if len(names) == 0 {
              fmt.Println("nobody to greet")
              return
          }
          for _, n := range names {
              fmt.Printf("Hello %sn", n)
          }
      }
      

      Agora, usando uma instrução if, se nenhum valor for enviado, o tamanho de names será 0 e vamos imprimir nobody to greet:

      Output

      nobody to greet Hello Sammy Hello Sammy Hello Jessica Hello Drew Hello Jamie

      O uso de um parâmetro variadic pode tornar seu código mais legível. Vamos criar uma função que junta as palavras com um delimitador específico. Criaremos esse programa sem uma função variadic primeiro para mostrar como ele seria lido:

      join.go

      package main
      
      import "fmt"
      
      func main() {
          var line string
      
          line = join(",", []string{"Sammy", "Jessica", "Drew", "Jamie"})
          fmt.Println(line)
      
          line = join(",", []string{"Sammy", "Jessica"})
          fmt.Println(line)
      
          line = join(",", []string{"Sammy"})
          fmt.Println(line)
      }
      
      func join(del string, values []string) string {
          var line string
          for i, v := range values {
              line = line + v
              if i != len(values)-1 {
                  line = line + del
              }
          }
          return line
      }
      

      Neste programa, estamos enviando uma vírgula (,) como o delimitador para a função join. Depois, enviamos uma fatia de valores para unir. Aqui está o resultado:

      Output

      Sammy,Jessica,Drew,Jamie Sammy,Jessica Sammy

      Como a função aceita uma fatia de string como o parâmetro values, tivemos que empacotar todas nossas palavras em uma fatia quando chamamos a função join. Isso pode tornar o código difícil de ler.

      Agora, vamos escrever a mesma função, mas usaremos uma função variadic:

      join.go

      package main
      
      import "fmt"
      
      func main() {
          var line string
      
          line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
          fmt.Println(line)
      
          line = join(",", "Sammy", "Jessica")
          fmt.Println(line)
      
          line = join(",", "Sammy")
          fmt.Println(line)
      }
      
      func join(del string, values ...string) string {
          var line string
          for i, v := range values {
              line = line + v
              if i != len(values)-1 {
                  line = line + del
              }
          }
          return line
      }
      

      Se executarmos o programa, podemos verificar que obtemos o mesmo resultado do programa anterior:

      Output

      Sammy,Jessica,Drew,Jamie Sammy,Jessica Sammy

      Embora ambas as versões da função join façam a mesma coisa em termos de programação, a versão variadic da função é muito mais fácil de ler quando ela está sendo chamada.

      Ordem do argumento variadic

      Você só pode ter um parâmetro variadic em uma função e ele deverá ser o último parâmetro definido na função. Definir parâmetros em uma função variadic em qualquer ordem que não seja o último parâmetro resultará em um erro de compilação:

      join.go

      package main
      
      import "fmt"
      
      func main() {
          var line string
      
          line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
          fmt.Println(line)
      
          line = join(",", "Sammy", "Jessica")
          fmt.Println(line)
      
          line = join(",", "Sammy")
          fmt.Println(line)
      }
      
      func join(values ...string, del string) string {
          var line string
          for i, v := range values {
              line = line + v
              if i != len(values)-1 {
                  line = line + del
              }
          }
          return line
      }
      

      Desta vez, colocamos primeiro o parâmetro values na função join. Isso causará o seguinte erro de compilação:

      Output

      ./join_error.go:18:11: syntax error: cannot use ... with non-final parameter values

      Ao definir qualquer função variadic, apenas o último parâmetro pode ser variadic.

      Destacando argumentos

      Até agora, vimos que podemos enviar zero, um, ou mais valores para uma função variadic. No entanto, haverá ocasiões em que teremos uma fatia de valores, os quais vamos querer enviar para uma função variadic.

      Vamos examinar nossa função join da última seção para ver o que acontece:

      join.go

      package main
      
      import "fmt"
      
      func main() {
          var line string
      
          names := []string{"Sammy", "Jessica", "Drew", "Jamie"}
      
          line = join(",", names)
          fmt.Println(line)
      }
      
      func join(del string, values ...string) string {
          var line string
          for i, v := range values {
              line = line + v
              if i != len(values)-1 {
                  line = line + del
              }
          }
          return line
      }
      

      Se executarmos este programa, vamos receber um erro de compilação:

      Output

      ./join-error.go:10:14: cannot use names (type []string) as type string in argument to join

      Embora a função variadic converta o parâmetro de values ...string em uma fatia de strings []string, não podemos enviar uma fatia de strings como argumento. Isso acontece porque o compilador espera argumentos discretos de strings.

      Para contornar esse problema, podemos destacar uma fatia, adicionando a ela um sufixo na forma de reticências (...) e transformando-a em argumentos discretos que serão enviados para uma função variadic:

      join.go

      package main
      
      import "fmt"
      
      func main() {
          var line string
      
          names := []string{"Sammy", "Jessica", "Drew", "Jamie"}
      
          line = join(",", names...)
          fmt.Println(line)
      }
      
      func join(del string, values ...string) string {
          var line string
          for i, v := range values {
              line = line + v
              if i != len(values)-1 {
                  line = line + del
              }
          }
          return line
      }
      

      Desta vez, quando chamamos a função join, destacamos a fatia names anexando reticências (...).

      Isso permite que o programa agora seja executado conforme esperado:

      Output

      Sammy,Jessica,Drew,Jamie

      É importante notar que ainda poderemos enviar zero, um, ou mais argumentos, assim como uma fatia que destacarmos. Aqui está o código que envia todas as variações que vimos até agora:

      join.go

      package main
      
      import "fmt"
      
      func main() {
          var line string
      
          line = join(",", []string{"Sammy", "Jessica", "Drew", "Jamie"}...)
          fmt.Println(line)
      
          line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
          fmt.Println(line)
      
          line = join(",", "Sammy", "Jessica")
          fmt.Println(line)
      
          line = join(",", "Sammy")
          fmt.Println(line)
      
      }
      
      func join(del string, values ...string) string {
          var line string
          for i, v := range values {
              line = line + v
              if i != len(values)-1 {
                  line = line + del
              }
          }
          return line
      }
      

      Output

      Sammy,Jessica,Drew,Jamie Sammy,Jessica,Drew,Jamie Sammy,Jessica Sammy

      Agora, sabemos como enviar zero, um, ou muitos argumentos, além de uma fatia que destacarmos para uma função variadic.

      Conclusão

      Neste tutorial, vimos como as funções variadic podem tornar seu código mais limpo. Embora nem sempre será necessário usá-las, você pode achá-las uteis:

      • Se achar que vai criar uma fatia temporária apenas para enviar para uma função.
      • Quando o número de parâmetros de entrada são desconhecidos ou irão variar quando chamados.
      • Para tornar seu código mais legível.

      Para aprender mais sobre como criar e chamar funções, você pode ler o artigo sobre Como definir e chamar funções em Go.



      Source link