One place for hosting & domains

      Como construir loops for no Go


      Introdução

      Em programação de computadores, um loop é uma estrutura de código que faz um loop para executar repetidamente uma parte de um código, frequentemente até que alguma condição seja alcançada. O uso de loops em programação de computadores permite que você automatize e repita tarefas semelhantes várias vezes. Vamos supor que você tivesse uma lista de arquivos que precisasse processar, ou se quisesse contar o número de linhas em um artigo. Você poderia usar um loop em seu código para resolver esses tipos de problemas.

      Na linguagem Go, um loop for implementa a execução repetida de um código baseado em um contador ou uma variável de loop. Ao contrário do que ocorre com outras linguagens de programação que têm vários constructos de looping como o while, do etc., o go tem somente o loop for. Isso serve para tornar seu código mais claro e mais legível, considerando que você não precisa se preocupar com várias estratégias para chegar no mesmo constructo de looping. Essa legibilidade aprimorada e a redução da carga cognitiva durante o desenvolvimento também tornarão o seu código menos propenso a erros do que com outras linguagens.

      Neste tutorial, você aprenderá como o loop for do Go funciona, incluindo as três grandes variações de sua utilização. Vamos começar mostrando como criar diferentes tipos de loops for, seguido de como fazer o loop através de tipos de dados sequenciais em Go. Vamos terminar explicando como usar os loops aninhados

      Declarando o ForClause e os loops de condição

      Para atender a uma variedade de casos de uso, existem três maneiras diferentes de criar loops for em Go, cada qual com seus próprios recursos. Essas maneiras são para criar um loop for com uma Condition, uma ForClause, ou uma RangeClause. Nesta seção, explicaremos como declarar e usar as variantes ForClause e Condição.

      Vamos ver como podemos usar um loop for com o ForClause primeiro.

      Um ForClause loop é definido como tendo uma instrução inicial, seguida de uma condição e, depois, uma instrução de post. Eles são organizados com a seguinte sintaxe:

      for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
          [Action]
      }
      

      Para explicar o que os componentes anteriores fazem, vejamos um loop for que incrementa por meio de uma gama especificada de valores usando a sintaxe do ForClause:

      for i := 0; i < 5; i++ {
          fmt.Println(i)
      }
      

      Vamos desmembrar esse loop e identificar cada parte.

      A primeira parte do loop é i := 0. Esta é a instrução inicial:

      for i := 0; i < 5; i++ {
          fmt.Println(i)
      }
      

      Essa instrução afirma que estamos declarando uma variável chamada i e definindo o valor inicial para 0.

      Em seguida, temos a condição:

      for i := 0; i < 5; i++ {
          fmt.Println(i)
      }
      

      Nessa condição, afirmamos que enquanto o i for menor do que o valor 5, o loop deve continuar em looping.

      Por fim, temos a instrução post:

      for i := 0; i < 5; i++ {
          fmt.Println(i)
      }
      

      Na instrução post, incrementamos a variável do loop i em um toda vez que uma iteração ocorrer, usando o operador de incremento i++.

      Quando executamos esse programa, o resultado fica parecido com este:

      Output

      0 1 2 3 4

      O loop executou 5 vezes. Inicialmente, ele definiu i para 0 e, depois, verificou se o i era menor do que 5. Como o valor de i era menor que 5, o loop executou e a ação de fmt.Println(i) foi executada. Após o loop terminar, o instrução post i++ foi chamada e o valor i foi incrementado em 1.

      Nota: tenha em mente que, em programação, tendemos a começar no índice 0, o que explica por que, a despeito da impressão de 5 números, eles variam de 0 a 4.

      Não estamos limitados a iniciar no 0 ou concluir em um valor especificado. Podemos atribuir qualquer valor para nossa instrução inicial e parar em qualquer valor em nossa instrução post. Isso nos permite criar qualquer intervalo desejado para fazer o loop:

      for i := 20; i < 25; i++ {
          fmt.Println(i)
      }
      

      Aqui, a iteração vai de 20 (inclusive) até 25 (exclusive), de modo que o resultado fica parecido com este:

      Output

      20 21 22 23 24

      Também podemos usar nossa instrução post para incrementar em diferentes valores. Esse procedimento é parecido com o step de outras linguagens:

      Primeiro, vamos usar uma instrução post com um valor positivo:

      for i := 0; i < 15; i += 3 {
          fmt.Println(i)
      }
      

      Neste caso, o loop for foi configurado para que os números de 0 a 15 sejam impressos, mas a incrementos de 3, de modo a imprimir apenas um número a cada três, desta forma:

      Output

      0 3 6 9 12

      Também podemos usar um valor negativo para que o nosso argumento de instrução post faça a iteração retroativamente. Teremos, porém, que ajustar devidamente nossa instrução inicial e os argumentos de condição:

      for i := 100; i > 0; i -= 10 {
          fmt.Println(i)
      }
      

      Aqui, definimos i para um valor inicial de 100, usamos a condição i < 0 para parar em 0 e a instrução post para diminuir o valor em 10 com o operador -=. O loop começa em 100 e termina em 0, diminuindo o valor em 10 a cada iteração. Podemos ver isso ocorrer no resultado:

      Output

      100 90 80 70 60 50 40 30 20 10

      Também é possível excluir a instrução inicial e a instrução post da sintaxe for e usar apenas a condição. Trata-se de um loop de Condição:

      i := 0
      for i < 5 {
          fmt.Println(i)
          i++
      }
      

      Desta vez, declaramos a variável i separadamente do loop for na linha anterior do código. O loop tem apenas uma cláusula de condição que verifica se o i é menor do que 5. Desde que a condição avalie como true, o loop continuará a iterar.

      Às vezes, você pode não saber o número de iterações que serão necessárias para concluir uma determinada tarefa. Neste caso, é possível omitir todas as instruções e usar a palavra-chave break para sair da execução:

      for {
          if someCondition {
              break
          }
          // do action here
      }
      

      Como exemplo disso, vamos supor que estivéssemos lendo uma estrutura de tamanho indeterminado como a de um buffer e não soubéssemos quando terminaríamos a leitura:

      buffer.go

      package main
      
      import (
          "bytes"
          "fmt"
          "io"
      )
      
      func main() {
          buf := bytes.NewBufferString("onentwonthreenfourn")
      
          for {
              line, err := buf.ReadString('n')
              if err != nil {
                  if err == io.EOF {
      
                      fmt.Print(line)
                      break
                  }
                  fmt.Println(err)
                  break
              }
              fmt.Print(line)
          }
      }
      

      No código anterior, o buf :=bytes.NewBufferString("onentwonthreenfourn") declara um buffer com alguns dados. Como não sabemos quando o buffer irá terminar a leitura, criamos um loop for sem cláusula. Dentro do loop for, usamos line, err := buf.ReadString('n') para ler uma linha do buffer e verificamos se existe um erro ao ler do buffer. Se houver, lidamos com o erro e usamos a palavra-chave break para sair do loop for. Com esses pontos de break, não é necessário incluir uma condição para interromper o loop.

      Nesta seção, aprendemos como declarar um loop do ForClause e a usá-lo para iterar por meio de uma gama conhecida de valores. Também aprendemos a usar um loop de condição para iterar até que uma condição específica seja cumprida. Em seguida, vamos aprender como o RangeClause é usado para iterar através de tipos de dados sequenciais.

      Na linguagem Go, é comum o uso de loops for para iterar sobre os elementos de tipos de dados sequenciais ou dados de coleta sequencial ou tipos de dados de coleta, como fatias, matrizes e strings. Para facilitar esse processo, podemos utilizar um loop for com a sintaxe do RangeClause. Embora você possa fazer loops em tipos de dados sequenciais usando a sintaxe do ForClause, a RangeClause é mais clara e fácil de ler.

      Antes de examinarmos o uso da RangeClause, vejamos como podemos iterar por meio de uma fatia, usando a sintaxe do ForClause:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
      
          for i := 0; i < len(sharks); i++ {
              fmt.Println(sharks[i])
          }
      }
      

      Executar isso dará o seguinte resultado, imprimindo cada um dos elementos da fatia:

      Output

      hammerhead great white dogfish frilled bullhead requiem

      Agora, vamos usar a RangeClause para executar o mesmo conjunto de ações:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
      
          for i, shark := range sharks {
              fmt.Println(i, shark)
          }
      }
      

      Neste caso, estamos imprimindo cada item da lista. Embora tenhamos usado as variáveis i e shark, poderíamos ter chamado as variáveis por qualquer outro nome de variável válido e, ainda assim, obteríamos o mesmo resultado:

      Output

      0 hammerhead 1 great white 2 dogfish 3 frilled 4 bullhead 5 requiem

      Ao usar range em uma fatia, ele irá sempre retornar dois valores. O primeiro valor será o índice em que a iteração atual do loop está e o segundo será o valor naquele índice. Neste caso, para a primeira iteração, o índice era 0, e o valor era hammerhead.

      Às vezes, queremos apenas o valor dentro dos elementos da fatia, não do índice. Se alterarmos o código anterior para imprimir apenas o valor, no entanto, vamos receber um erro de tempo de compilação:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
      
          for i, shark := range sharks {
              fmt.Println(shark)
          }
      }
      

      Output

      src/range-error.go:8:6: i declared and not used

      Como o i foi declarado no loop for, mas nunca foi usado, o compilador responderá com o erro i declared and not used. Este é o mesmo erro que você receberá no Go sempre que for declarar uma variável e não a utilizar.

      Por isso, o Go tem o identificador em branco, que é um sublinhado (_). Em um loop for, é possível utilizar o identificador em branco para ignorar qualquer valor retornado da palavra-chave range. Neste caso, queremos ignorar o índice, que é o primeiro argumento retornado.

      main.go

      package main
      
      import "fmt"
      
      func main() {
          sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
      
          for _, shark := range sharks {
              fmt.Println(shark)
          }
      }
      

      Output

      hammerhead great white dogfish frilled bullhead requiem

      Esse resultado mostra que o loop for iterou por toda a fatia de strings e imprimiu cada item da fatia sem o índice.

      Também é possível usar o range para adicionar itens a uma lista:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
      
          for range sharks {
              sharks = append(sharks, "shark")
          }
      
          fmt.Printf("%qn", sharks)
      }
      

      Output

      ['hammerhead', 'great white', 'dogfish', 'frilled', 'bullhead', 'requiem', 'shark', 'shark', 'shark', 'shark', 'shark', 'shark']

      Aqui, adicionamos uma string com espaço reservado de "shark"para cada item do comprimento da fatia sharks.

      Note que não precisamos usar o identificador em branco _ para ignorar nenhum dos valores retornados do operador range. O Go nos permite omitir toda a parte da instrução range se não precisarmos usar qualquer um do valores retornados.

      Também podemos usar o operador range para preencher valores de uma fatia:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          integers := make([]int, 10)
          fmt.Println(integers)
      
          for i := range integers {
              integers[i] = i
          }
      
          fmt.Println(integers)
      }
      

      Neste exemplo, a fatia integers é inicializada com dez valores em branco, mas o loop for define todos os valores desta forma:

      Output

      [0 0 0 0 0 0 0 0 0 0] [0 1 2 3 4 5 6 7 8 9]

      A primeira vez que imprimimos o valor da fatia integers, vemos todos os zeros. Então, iteramos pro meio de cada índice e definimos o valor para o índice atual. Em seguida, imprimimos o valor de integers uma segunda vez, mostrando que todos eles agora têm um valor de 0 a 9.

      Também podemos usar o operador range para iterar por meio de cada caractere em uma string:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          sammy := "Sammy"
      
          for _, letter := range sammy {
              fmt.Printf("%cn", letter)
          }
      }
      

      Output

      S a m m y

      Ao iterar por um mapa, o range retornará a key (chave) e o** value** (valor):

      main.go

      package main
      
      import "fmt"
      
      func main() {
          sammyShark := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
      
          for key, value := range sammyShark {
              fmt.Println(key + ": " + value)
          }
      }
      

      Output

      color: blue location: ocean name: Sammy animal: shark

      Nota: é importante notar que a ordem na qual um mapa retorna é aleatória. Cada vez que você executa esse programa, você pode obter um resultado diferente.

      Agora que aprendemos como iterar em dados sequenciais com loops for do tipo range, vamos ver como usar loops dentro de loops.

      Loops for aninhados

      Assim como acontece em outras linguagens de programação, os loops também podem ser aninhados em Go. Nesting (aninhamento) é quando temos um constructo dentro de outro. Neste caso, um loop aninhado é um loop que ocorre dentro de outro loop. Eles podem ser úteis quando o que se quer é uma ação em loop sendo realizada em cada elemento de um conjunto de dados.

      Os loops aninhados são estruturalmente semelhantes às instruções aninhadas if. Eles são construídos desta forma:

      for {
          [Action]
          for {
              [Action]  
          }
      }
      

      Primeiro, o programa encontra o loop externo, executando sua primeira iteração. Essa primeira iteração aciona o loop interno, o loop aninhado, o qual é executado até sua finalização. Em seguida, o programa retorna para o topo do loop externo, finalizando a segunda iteração e acionando novamente o loop aninhado. Novamente, o loop aninhado executa até sua finalização e o programa retorna para o topo do loop externo até a sequência estar completa ou que uma instrução break ou outra interrompa o processo.

      Vamos implementar um loop for aninhado para analisarmos melhor. Neste exemplo, o loop externo irá iterar por uma fatia de inteiros chamada de numList e o loop interno irá iterar por uma fatia de strings chamada alphaList.

      main.go

      package main
      
      import "fmt"
      
      func main() {
          numList := []int{1, 2, 3}
          alphaList := []string{"a", "b", "c"}
      
          for _, i := range numList {
              fmt.Println(i)
              for _, letter := range alphaList {
                  fmt.Println(letter)
              }
          }
      }
      

      Ao executarmos esse programa, vamos receber o seguinte resultado:

      Output

      1 a b c 2 a b c 3 a b c

      O resultado ilustra que o programa termina a primeira iteração do loop externo imprimindo 1, que, por sua vez, aciona a conclusão do loop interno, imprimindo a, b e c, consecutivamente. Assim que o loop interno for finalizado, o programa retorna para o topo do loop externo, imprime o número 2, e imprime novamente o loop interno em sua totalidade (a, b, c) etc.

      Os loops for aninhados podem ser úteis para iterar através de itens dentro de fatias compostas por fatias. Em uma fatia composta por fatias, se usarmos apenas um loop for, o programa dará como resultado cada lista interna como um item:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          ints := [][]int{
              []int{0, 1, 2},
              []int{-1, -2, -3},
              []int{9, 8, 7},
          }
      
          for _, i := range ints {
              fmt.Println(i)
          }
      }
      

      Output

      [0 1 2] [-1 -2 -3] [9 8 7]

      Para acessar cada item individual das fatias internas, implementaremos um loop for aninhado:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          ints := [][]int{
              []int{0, 1, 2},
              []int{-1, -2, -3},
              []int{9, 8, 7},
          }
      
          for _, i := range ints {
              for _, j := range i {
                  fmt.Println(j)
              }
          }
      }
      

      Output

      0 1 2 -1 -2 -3 9 8 7

      Ao usarmos um loop for aninhado aqui, podemos iterar com os itens individuais contidos nas fatias.

      Conclusão

      Neste tutorial, aprendemos a declarar e usar loops for para resolver tarefas repetitivas no Go. Também aprendemos as três diferentes variações de um loop for e quando usá-las. Para aprender mais sobre os loops for e como controlar o fluxo deles, leia o artigo Usando as instruções break e continue ao trabalhar com loops em Go.



      Source link

      Usando instruções break e continue ao trabalhar com loops em Go


      Introdução

      O uso de loops do tipo “for” em Go permite que você automatize e repita tarefas de maneira eficiente.

      Aprender como controlar a operação e o fluxo dos loops permitirá uma lógica personalizada em seu programa. É possível controlar seus loops com as instruções break [interromper] e continue [continuar].

      Instrução break

      Em Go, a instrução break termina a execução do loop atual. Uma break está quase sempre pareada com uma instrução condicional if.

      Vamos ver um exemplo que usa a instrução break em um loop do tipo "for":

      break.go

      package main
      
      import "fmt"
      
      func main() {
          for i := 0; i < 10; i++ {
              if i == 5 {
                  fmt.Println("Breaking out of loop")
                  break // break here
              }
              fmt.Println("The value of i is", i)
          }
          fmt.Println("Exiting program")
      }
      

      Este pequeno programa cria um loop do tipo "for" que irá iterar enquanto i for menor que 10.

      Dentro do loop do tipo "for", há uma instrução if. A instrução if testa a condição de i para ver se o valor é menor que 5. Se o valor i não for igual a 5, o loop continua e imprime o valor de i. Se o valor de i for igual a 5, o loop irá executar a instrução break, imprimir que ele está Breaking out of loop [Saindo do loop] e parar de executar o loop. Ao final do programa, imprimimos Exiting program [Saindo do programa] para exprimir que saímos do loop.

      Quando executarmos esse código, nosso resultado será o seguinte:

      Output

      The value of i is 0 The value of i is 1 The value of i is 2 The value of i is 3 The value of i is 4 Breaking out of loop Exiting program

      Isso mostra que, uma vez que o número inteiro i é avaliado como equivalente a 5, o loop interrompe, uma vez que o programa é orientado a fazer isso com a instrução break.

      Loops aninhados

      É importante lembrar que a instrução break irá parar apenas a execução do loop mais interno em que for chamada. Se tiver um conjunto aninhado de loops, será necessário uma interrupção para cada loop se desejar.

      nested.go

      package main
      
      import "fmt"
      
      func main() {
          for outer := 0; outer < 5; outer++ {
              if outer == 3 {
                  fmt.Println("Breaking out of outer loop")
                  break // break here
              }
              fmt.Println("The value of outer is", outer)
              for inner := 0; inner < 5; inner++ {
                  if inner == 2 {
                      fmt.Println("Breaking out of inner loop")
                      break // break here
                  }
                  fmt.Println("The value of inner is", inner)
              }
          }
          fmt.Println("Exiting program")
      }
      

      Neste programa, temos dois loops. Embora ambos iterem 5 vezes, cada um tem uma instrução condicional if com uma instrução break. O loop exterior será interrompido se o valor outer for igual a 3. O loop interno será interrompido se o valor inner for 2.

      Se executarmos o programa, veremos o seguinte resultado:

      Output

      The value of outer is 0 The value of inner is 0 The value of inner is 1 Breaking out of inner loop The value of outer is 1 The value of inner is 0 The value of inner is 1 Breaking out of inner loop The value of outer is 2 The value of inner is 0 The value of inner is 1 Breaking out of inner loop Breaking out of outer loop Exiting program

      Note que cada vez que o loop interno é interrompido, o loop exterior não é. Isso acontece porque o break irá interromper apenas o loop mais interno de onde for chamado.

      Vimos de que maneira o uso da instrução break irá interromper a execução de um loop. Em seguida, vamos ver como é possível continuar a iteração de um loop.

      Instrução continue

      A instrução continue é usada quando você quer pular a parte restante do loop, retornar ao topo do loop e dar continuidade a uma nova iteração.

      Tal como com a instrução break, a instrução continue é comumente usada com uma instrução condicional if.

      Usando o mesmo programa de loop do tipo "for" que na seção anterior da Instrução break, usaremos uma instrução continue, em vez de uma instrução break:

      continue.go

      package main
      
      import "fmt"
      
      func main() {
          for i := 0; i < 10; i++ {
              if i == 5 {
                  fmt.Println("Continuing loop")
                  continue // break here
              }
              fmt.Println("The value of i is", i)
          }
          fmt.Println("Exiting program")
      }
      

      A diferença entre usar a instrução continue, em vez de uma instrução break, é que o nosso código continuará apesar da interrupção quando a variável i for avaliada como equivalente a 5. Vamos ver nosso resultado:

      Output

      The value of i is 0 The value of i is 1 The value of i is 2 The value of i is 3 The value of i is 4 Continuing loop The value of i is 6 The value of i is 7 The value of i is 8 The value of i is 9 Exiting program

      Aqui, vemos que a linha The value of i is 5 [O valor de i é 5] nunca ocorre no resultado, mas o loop continua após aquele ponto para imprimir linhas para os números 6-10 antes de sair do loop.

      Você pode usar a instrução continue para evitar um código condicional extremamente aninhado, ou para otimizar um loop, eliminando casos que ocorram com frequência e que você gostaria de rejeitar.

      A instrução continue faz com que um programa pule certos fatores que surjam dentro de um loop, mas depois continuem pelo restante do loop.

      Conclusão

      As instruções break e continue em Go permitirão que você use loops do tipo "for" de maneira mais eficaz em seu código.



      Source link

      Learning Go Functions, Loops, and Errors – A Tutorial


      Updated by Linode Contributed by Mihalis Tsoukalos

      Introduction

      Go is a modern, open source, and general-purpose programming language that began as an internal Google project and was officially announced at the end of 2009. Go was inspired by many other programming languages including C, Pascal, Alef, and Oberon. Its spiritual fathers were Robert Griesemer, Ken Thomson, and Rob Pike, who all designed Go as a language for professional programmers that want to build reliable, robust, and efficient software. Apart from its syntax and its standard functions, Go comes with a rich standard library.

      In this Guide

      This guide will cover the following topics:

      Note

      This guide was written with Go version 1.13.

      Before You Begin

      1. You will need Go installed on your computer. To get it, go to Go’s official download page and get the installer for your operating system, or you can install it from source. Follow the installation instructions for your operating system.

      2. Add /usr/local/go/bin to the PATH environment variable:

        export PATH=$PATH:/usr/local/go/bin
        

        You may need to restart your shell for this change to apply.

      The Advantages of Go

      Although Go is not perfect, it has many advantages, including the following:

      • It is a modern programming language that was made by experienced developers for developers.
      • The code is easy to read.
      • Go keeps concepts orthogonal, or simple, because a few orthogonal features work better than many overlapping ones.
      • The compiler prints practical warnings and error messages that help you solve the actual problem.
      • It has support for procedural, concurrent, and distributed programming.
      • Go supports garbage collection so you do not have to deal with memory allocation and deallocation.
      • Go can be used to build web applications and it provides a simple web server for testing purposes.
      • The standard Go library offers many packages that simplify the work of the developer.
      • It uses static linking by default, which means that the produced binary files can be easily transferred to other machines with the same OS and architecture. As a consequence, once a Go program is compiled successfully and the executable file is generated, the developer does not need to worry about dependencies and library versions.
      • The code is portable, especially among UNIX machines.
      • Go can be used for writing UNIX systems software.
      • It supports Unicode by default which means that you do not need any extra code for printing characters from multiple human languages or symbols.

      Executing Go code

      There are two kinds of Go programs: autonomous programs that are executable, and Go libraries. Go does not care about an autonomous program’s file name. What matters is that the package name is main and that there is a single main() function in it. This is because the main() function is where program execution begins. As a result, you cannot have multiple main() functions in the files of a single project.

      A Simple Go program

      This is the Go version of the Hello World program:

      ./helloworld.go
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      package main
      
      import (
          "fmt"
      )
      
      func main() {
          fmt.Println("Hello World!")
      }
      • All Go code is delivered within Go packages. For executable programs, the package name should be main. Package declarations begin with the package keyword.

      • Executable programs should have a function named main() without any function parameters. Function definitions begin with the func keyword.

      • Go packages might include import statements for importing Go packages. However, Go demands that you use some functionality from each one of the packages that you import. There is a way to bypass this rule, however, it is considered a bad practice to do this.

        The helloworld.go file above imports the fmt package and uses the fmt.Println() function from that package.

        Note

        All exported package functions begin with an uppercase letter. This follows the Go rule: if you export something outside the current package, it should begin with an uppercase letter. This rule applies even if the field of the Go structure or the global variable is included in a Go package.

      • Go statements do not need to end with a semicolon. However, you are free to use semicolons if you wish. For more information on formatting with curly braces, see the section below.

      1. Now that you better understand the helloworld.go program, execute it with the go run command:

        go run helloworld.go
        

        You will see the following output:

          
        Hello World!
        
        

        This is the simplest of two ways that you can execute Go code. The go run command compiles the code and creates a temporary executable file that is automatically executed and then it deletes that temporary executable file. This is similar to using a scripting programming language.

      2. The second method to execute Go code is to use the build command. Run the following command to use this method:

        go build helloworld.go
        

        The result of that command is a binary executable file that you have to manually execute. This method is similar to the way you execute C code on a UNIX machine. The executable file is named after the Go source filename, which means that in this case the result will be an executable file named helloworld. Go creates statically linked executable files that have no dependencies to external libraries.

      3. Execute the helloworld file:

        ./helloworld
        

        You will see the following output:

          
        Hello World!
        
        

        Note

        The go run command is usually used while experimenting and developing new Go projects. However, if you need to transfer an executable file to another system with the same architecture, you should use go build.

      Formatting Curly Braces

      The following version of the “Hello World” program will not compile:

      ./curly.go
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      package main
      
      import (
          "fmt"
      )
      
      func main()
      {
          fmt.Println("Hello World!")
      }
      1. Execute the program above, and observer the error message generated by the compiler:

        go run curly.go
        
          
        # command-line-arguments
        ./curly.go:7:6: missing function body
        ./curly.go:8:1: syntax error: unexpected semicolon or newline before {
        
        
      • This error message is generated because Go requires the use of semicolons as statement terminators in many contexts and the compiler automatically inserts the required semicolons when it thinks that they are necessary. Putting the opening curly brace ({) on its own line makes the Go compiler look for a semicolon at the end of the previous line (func main()), which is the cause of the error message.

      • There is only one way to format curly braces in Go; the opening curly brace must not appear on it’s own line. Additionally, you must use curly braces even if a code block contains a single Go statement, like in the body of a for loop. You can see an example of this in the first version of the helloworld.go program or in the Loops in Go section.

      The Assignment Operator and Short Variable Declarations

      • Go supports assignment (=) operators and short variable declarations (:=).
      • With := you can declare a variable and assign a value to it at the same time. The type of the variable is inferred from the given value.
      • You can use = in two cases. First, to assign a new value to an existing variable and second, to declare a new variable, provided that you also give its type.

        For example, var aVariable int = 10, is equivalent to aVariable := 10 assuming aVariable is an int.

      • When you specifically want to control a variable’s type, it is safer to declare the variable and its type using var and then assign a value to it using =.

      Loops in Go

      The file loops.go demonstrates loops in Go:

      ./loops.go
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      
      package main
      
      import (
          "fmt"
      )
      
      func main() {
          for loopIndex := 0; loopIndex < 20; loopIndex++ {
              if loopIndex%10 == 0 {
                  continue
              }
      
              if loopIndex == 19 {
                  break
              }
              fmt.Print(loopIndex, " ")
          }
          fmt.Println()
      
          // Use break to exit the for loop
          loopIndex := 10
          for {
              if loopIndex < 0 {
                  break
              }
              fmt.Print(loopIndex, " ")
              loopIndex--
          }
          fmt.Println()
      
          // This is similar to a while(true) do something loop
          loopIndex = 0
          anExpression := true
          for ok := true; ok; ok = anExpression {
              if loopIndex > 10 {
                  anExpression = false
              }
      
              fmt.Print(loopIndex, " ")
              loopIndex++
          }
          fmt.Println()
      
          anArray := [5]int{0, 1, -1, 2, -2}
          for loopIndex, value := range anArray {
              fmt.Println("index:", loopIndex, "value: ", value)
          }
      }
      • There are two types of for loops in Go. Traditional for loops that use a control variable initialization, condition, and afterthought; and those that iterate over the elements of a Go data type such as an array or a map using the range keyword.

      • Go has no direct support for while loops. If you want to use a while loop, you can emulate it with a for loop.

      • In their simplest form, for loops allow you to iterate, a predefined number of times, for as long as a condition is valid, or according to a value that is calculated at the beginning of the for loop. Such values include the size of a slice or an array, or the number of keys on a map. However, range is more often used for accessing all the elements of a slice, an array, or a map because you do not need to know the object’s cardinality in order to process its elements one by one. For simplicity, this example uses an array, and a later example will use a slice.

      • You can completely exit a for loop using the break keyword. The break keyword also allows you to create a for loop without an exit condition because the exit condition can be included in the code block of the for loop. You are also allowed to have multiple exit conditions in a for loop.

      • You can skip a single iteration of a for loop using the continue keyword.

      1. Execute the loops.go program:

        go run loops.go
        

        You will see the following output:

          
        1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18
        10 9 8 7 6 5 4 3 2 1 0
        0 1 2 3 4 5 6 7 8 9 10 11
        index: 0 value:  0
        index: 1 value:  1
        index: 2 value:  -1
        index: 3 value:  2
        index: 4 value:  -2
            
        

      Functions in Go

      Functions are first class citizens in Go, which means that functions can be parameters to other functions as well as returned by functions. This section will illustrate various types of functions.

      Go also supports anonymous functions. These can be defined inline without the need for a name and they are usually used for implementing operations that require a small amount of code. In Go, a function can return an anonymous function or take an anonymous function as one of its arguments. Additionally, anonymous functions can be attached to Go variables. In functional programming terminology anonymous functions are called closures. It is considered a good practice for anonymous functions to have a small implementation and a local focus.

      Regular functions

      This section will present the implementation of some traditional functions.

      ./functions.go
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      
      package main
      
      import (
          "fmt"
      )
      
      func doubleSquare(firstNum int) (int, int) {
          return firstNum * 2, firstNum * firstNum
      }
      
      func namedMinMax(firstNum, secondNum int) (min, max int) {
          if firstNum > secondNum {
              min = secondNum
              max = firstNum
          } else {
              min = firstNum
              max = secondNum
          }
          return
      }
      
      func minMax(firstNum, secondNum int) (min, max int) {
          if firstNum > secondNum {
              min = secondNum
              max = firstNum
          } else {
              min = firstNum
              max = secondNum
          }
          return min, max
      }
      
      func main() {
          secondNum := 10
      
          square := func(numberToSquare int) int {
              return numberToSquare * numberToSquare
          }
          fmt.Println("The square of", secondNum, "is", square(secondNum))
      
          double := func(numberToDouble int) int {
              return numberToDouble + numberToDouble
          }
          fmt.Println("The double of", secondNum, "is", double(secondNum))
      
          fmt.Println(doubleSquare(secondNum))
          doubledNumber, squaredNumber := doubleSquare(secondNum)
          fmt.Println(doubledNumber, squaredNumber)
      
          value1 := -10
          value2 := -1
          fmt.Println(minMax(value1, value2))
          min, max := minMax(value1, value2)
          fmt.Println(min, max)
          fmt.Println(namedMinMax(value1, value2))
          min, max = namedMinMax(value1, value2)
          fmt.Println(min, max)
      }
      • The main() function takes no arguments and returns no arguments. Once the special function main() exits, the program automatically ends.

      • The doubleSquare() function requires a single int parameter and returns two int values, which is defined as (int, int).

      • All function arguments must have a name – variadic functions are the only exception to this rule.

      • If a function returns a single value, you do not need to put parenthesis around its type.

      • Because namedMinMax() has named return values in its signature, the min and max parameters are automatically returned in the order in which they were put in the function definition. Therefore, the function does not need to explicitly return any variables or values in its return statement at the end, and does not. minMax() function has the same functionality as namedMinMax() but it explicitly returns its values demonstrating that both ways are valid.

      • Both square and double variables in main() are assigned an anonymous function. However, nothing stops you from changing the value of square, double, or any other variable that holds the result of an anonymous function, afterwards. This means that both variables may have a different value in the future.

      1. Execute the functions.go program.

        go run functions.go
        

        Your output will resemble the following:

          
        The square of 10 is 100
        The double of 10 is 20
        20 100
        20 100
        -10 -1
        -10 -1
        -10 -1
        -10 -1
            
        

      Variadic functions

      Variadic functions are functions that accept a variable number of arguments. The most popular variadic functions in Go can be found in the fmt package. The code of variadic.go illustrates the creation and the use of variadic functions.

      ./variadic.go
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      
      package main
      
      import (
          "fmt"
      )
      
      func varFunc(input ...string) {
          fmt.Println(input)
      }
      
      func oneByOne(message string, sliceOfNumbers ...int) int {
          fmt.Println(message)
          sum := 0
          for indexInSlice, sliceElement := range sliceOfNumbers {
              fmt.Print(indexInSlice, sliceElement, "t")
              sum = sum + sliceElement
          }
          fmt.Println()
          sliceOfNumbers[0] = -1000
          return sum
      }
      
      func main() {
          many := []string{"12", "3", "b"}
          varFunc(many...)
          sum := oneByOne("Adding numbers...", 1, 2, 3, 4, 5, -1, 10)
          fmt.Println("Sum:", sum)
          sliceOfNumbers := []int{1, 2, 3}
          sum = oneByOne("Adding numbers...", sliceOfNumbers...)
          fmt.Println(sliceOfNumbers)
      }
      • The ... operator used as a prefix to a type like ...int is called the pack operator, whereas the unpack operator appends a slice like sliceOfNumbers.... A slice is a Go data type that is essentially an abstraction of an array of unspecified length.

      • Each variadic function can use the pack operator once. The oneByOne() function accepts a single string and a variable number of integer arguments using the sliceOfNumbers slice.

      • The varFunc function accepts a single argument and just calls the fmt.Println() function.

      • Another note about slices: the second call to oneByOne() is using a slice. Any changes you make to that slice inside the variadic function will persist after the function exits because this is how slices work in Go.

      1. Execute the variadic.go program:

        go run variadic.go
        

        The output will resemble the following

          
        [12 3 b]
        Adding numbers...
        0 1     1 2     2 3     3 4     4 5     5 -1     6 10
        Sum: 24
        Adding numbers...
        0 1     1 2     2 3
        [-1000 2 3]
            
        

      Functions and pointer variables

      Go supports pointers and this section will briefly present how functions can work with pointers. A future Go guide will talk about pointers in more detail, but here is a brief overview.

      ./fPointers.go
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      
      package main
      
      import (
          "fmt"
      )
      
      func getPointer(varToPointer *float64) float64 {
          return *varToPointer * *varToPointer
      }
      
      func returnPointer(testValue int) *int {
          squareTheTestValue := testValue * testValue
          return &squareTheTestValue
      }
      
      func main() {
          testValue := -12.12
          fmt.Println(getPointer(&testValue))
          testValue = -12
          fmt.Println(getPointer(&testValue))
      
          theSquare := returnPointer(10)
          fmt.Println("sq value:", *theSquare)
          fmt.Println("sq memory address:", theSquare)
      }
      • The getPointer() function takes a pointer argument to a float64, which is defined as varToPointer *float64, where returnPointer() returns a pointer to an int, which is declared as *int.
      1. Execute the fPointers.go program:

        go run fPointers.go
        

        The output will resemble the following:

          
        146.8944
        144
        sq value: 100
        sq memory address: 0xc00001a0b8
            
        

      Functions with Functions as Parameters

      Go functions can have functions as parameters.

      ./fArgF.go
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      
      package main
      
      import "fmt"
      
      func doubleIt(numToDouble int) int {
          return numToDouble + numToDouble
      }
      
      func squareIt(numToSquare int) int {
          return numToSquare * numToSquare
      }
      
      func funFun(functionName func(int) int, variableName int) int {
          return functionName(variableName)
      }
      
      func main() {
          fmt.Println("funFun Double:", funFun(doubleIt, 12))
          fmt.Println("funFun Square:", funFun(squareIt, 12))
          fmt.Println("Inline", funFun(func(numToCube int) int { return numToCube * numToCube * numToCube }, 12))
      }
      • The funFun() function accepts two parameters, a function parameter named functionName and an int value. The functionName parameter should be a function that takes one int argument and returns an int value.

      • The first fmt.Println() call in main() uses funFun() and passes the doubleIt function, without any parentheses, as its first parameter.

      • The second fmt.Println() call uses funFun() with squareIt as its first parameter.

      • In the last fmt.Println() statement the implementation of the function parameter is defined inside the call to funFun() using an anonymous function.

      1. Execute the fArgF.go program:

        go run fArgF.go
        

        The output will resemble the following:

          
        function1: 24
        function2: 144
        Inline 1728
            
        

      Functions Returning Functions

      Go functions can return functions.

      ./fRetF.go
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      
      package main
      
      import (
          "fmt"
      )
      
      func squareFunction() func() int {
          numToSquare := 0
          return func() int {
              numToSquare++
              return numToSquare * numToSquare
          }
      }
      
      func main() {
          square1 := squareFunction()
          square2 := squareFunction()
      
          fmt.Println("First Call to square1:", square1())
          fmt.Println("Second Call to square1:", square1())
          fmt.Println("First Call to square2:", square2())
          fmt.Println("Third Call to square1:", square1())
      }
      • squareFunction() returns an anonymous function with the func() int signature.

      • As squareFunction() is called two times, you will need to use two separate variables, square1 and square2 to keep the two return values.

      1. Execute the fRetF.go program:

        go run fRetF.go
        

        Your output will resemble the following:

          
        First Call to square1: 1
        Second Call to square1: 4
        First Call to square2: 1
        Third Call to square1: 9
            
        

        Notice that the values of square1 and square2 are not connected even though they both came from squareFunction().

      Errors in Go

      Errors and error handling are two important topics in Go. Go puts so much importance on error messages that it has a dedicated data type for errors, aptly named error. This also means that you can easily create your own error messages if you find that what Go gives you is not adequate. You will most likely need to create and handle your own errors when you are developing your own Go packages.

      Recognizing an error condition is one task, while deciding how to react to an error condition is another task. Therefore, some error conditions might require that you immediately stop the execution of the program, whereas in other error situations, you might just print a warning message and continue.

      ./errors.go
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      
      package main
      
      import (
          "errors"
          "fmt"
          "strconv"
      )
      
      func main() {
      
          customError := errors.New("My Custom Error!")
          if customError.Error() == "My Custom Error!" {
              fmt.Println("!!")
          }
      
          stringToConvert1 := "123"
          stringToConvert2 := "43W"
          _, err := strconv.Atoi(stringToConvert1)
          if err != nil {
              fmt.Println(err)
              return
          }
      
          _, err = strconv.Atoi(stringToConvert2)
          if err != nil {
              fmt.Println(err)
              return
          }
      }
      • The strconv.Atoi() function tries to convert a string into an integer, provided that the string is a valid integer, and returns two things, an integer value and an error variable. If the error variable is nil, then the conversion was successful and you get a valid integer. The _ character tells Go to ignore one, as in this case, or more of the return values of a function.

      • Most of the time, you need to check whether an error variable is equal to nil and then act accordingly. This kind of Go code is very popular in Go programs and you will see it and use it multiple times.

      • Also presented here is the errors.New() function that allows you to create a custom error message and errors.Error() function that allows you to convert an error variable into a string variable.

      1. Execute the errors.go program:

        go run errors.go
        

        Your output will resemble the following:

          
        !!
        strconv.Atoi: parsing "43W": invalid syntax
            
        

      Summary

      In this guide you learned the basics about the Go programming language, how to execute programs, how to write loops, how to handle errors, and you saw examples for various function types.

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link