Go - Guia Rápido

Go é uma linguagem de propósito geral projetada com a programação de sistemas em mente. Foi inicialmente desenvolvido no Google no ano de 2007 por Robert Griesemer, Rob Pike e Ken Thompson. É fortemente e estaticamente tipado, fornece suporte embutido para coleta de lixo e oferece suporte à programação simultânea.

Os programas são construídos usando pacotes, para gerenciamento eficiente de dependências. As implementações de programação Go usam um modelo tradicional de compilação e link para gerar binários executáveis. A linguagem de programação Go foi anunciada em novembro de 2009 e é usada em alguns dos sistemas de produção do Google.

Recursos da programação Go

Os recursos mais importantes da programação Go estão listados abaixo -

  • Suporte para ambiente adotando padrões semelhantes a linguagens dinâmicas. Por exemplo, digite inferência (x: = 0 é uma declaração válida de uma variável x do tipo int)

  • O tempo de compilação é rápido.

  • Suporte de simultaneidade embutido: processos leves (via rotinas go), canais, instrução select.

  • Os programas Go são simples, concisos e seguros.

  • Suporte para Interfaces e incorporação de tipo.

  • Produção de binários nativos estaticamente vinculados sem dependências externas.

Recursos excluídos intencionalmente

Para manter a linguagem simples e concisa, os seguintes recursos comumente disponíveis em outros idiomas semelhantes foram omitidos no Go -

  • Suporte para herança de tipo

  • Suporte para método ou sobrecarga do operador

  • Suporte para dependências circulares entre pacotes

  • Suporte para aritmética de ponteiro

  • Suporte para afirmações

  • Suporte para programação genérica

Programas Go

Um programa Go pode variar em comprimento de 3 a milhões de linhas e deve ser escrito em um ou mais arquivos de texto com a extensão ".go". Por exemplo, hello.go.

Você pode usar "vi", "vim" ou qualquer outro editor de texto para gravar seu programa Go em um arquivo.

Configuração de ambiente local

Se você ainda deseja configurar seu ambiente para a linguagem de programação Go, você precisa dos dois softwares a seguir disponíveis em seu computador -

  • Um editor de texto
  • Compilador Go

Editor de texto

Você precisará de um editor de texto para digitar seus programas. Exemplos de editores de texto incluem o bloco de notas do Windows, comando Editar sistema operacional, Brief, Epsilon, EMACS e vim ou vi.

O nome e a versão dos editores de texto podem variar em diferentes sistemas operacionais. Por exemplo, o Bloco de notas é usado no Windows e o vim ou vi é usado no Windows, bem como no Linux ou UNIX.

Os arquivos que você cria com o editor de texto são chamados source files. Eles contêm o código-fonte do programa. Os arquivos de origem para programas Go são normalmente nomeados com a extensão".go".

Antes de iniciar sua programação, certifique-se de ter um editor de texto instalado e de ter experiência suficiente para escrever um programa de computador, salvá-lo em um arquivo, compilá-lo e finalmente executá-lo.

O compilador Go

O código-fonte escrito no arquivo-fonte é a fonte legível para o seu programa. Ele precisa ser compilado e transformado em linguagem de máquina para que sua CPU possa realmente executar o programa de acordo com as instruções fornecidas. O compilador da linguagem de programação Go compila o código-fonte em seu programa executável final.

A distribuição Go vem como um binário instalável para FreeBSD (versão 8 e superior), Linux, Mac OS X (Snow Leopard e superior) e sistemas operacionais Windows com arquiteturas de processador x86 de 32 bits (386) e 64 bits (amd64).

A seção a seguir explica como instalar a distribuição binária Go em vários sistemas operacionais.

Baixar Arquivo Go

Baixe a versão mais recente do arquivo compactado instalável Go em Downloads do Go . A seguinte versão é usada neste tutorial: go1.4.windows-amd64.msi .

Ele é copiado para a pasta C: \> go.

SO Nome do arquivo
janelas go1.4.windows-amd64.msi
Linux go1.4.linux-amd64.tar.gz
Mac go1.4.darwin-amd64-osx10.8.pkg
FreeBSD go1.4.freebsd-amd64.tar.gz

Instalação em UNIX / Linux / Mac OS X e FreeBSD

Extraia o arquivo de download para a pasta / usr / local, criando uma árvore Go em / usr / local / go. Por exemplo -

tar -C / usr / local -xzf go1.4.linux-amd64.tar.gz

Adicione / usr / local / go / bin à variável de ambiente PATH.

SO Resultado
Linux exportar PATH = $ PATH: / usr / local / go / bin
Mac exportar PATH = $ PATH: / usr / local / go / bin
FreeBSD exportar PATH = $ PATH: / usr / local / go / bin

Instalação em Windows

Use o arquivo MSI e siga as instruções para instalar as ferramentas Go. Por padrão, o instalador usa a distribuição Go em c: \ Go. O instalador deve definir o diretório c: \ Go \ bin na variável de ambiente PATH do Windows. Reinicie todos os prompts de comando abertos para que a alteração tenha efeito.

Verificando a instalação

Crie um arquivo go chamado test.go em C:\>Go_WorkSpace.

Arquivo: test.go

package main

import "fmt"

func main() {
   fmt.Println("Hello, World!")
}

Agora execute test.go para ver o resultado -

C:\Go_WorkSpace>go run test.go

Resultado

Hello, World!

Antes de estudarmos os blocos de construção básicos da linguagem de programação Go, vamos primeiro discutir a estrutura mínima dos programas Go para que possamos tomá-la como uma referência nos capítulos subsequentes.

Hello World Example

Um programa Go consiste basicamente nas seguintes partes -

  • Declaração da embalagem
  • Importar Pacotes
  • Functions
  • Variables
  • Declarações e Expressões
  • Comments

Vejamos um código simples que imprimiria as palavras "Hello World" -

package main

import "fmt"

func main() {
   /* This is my first sample program. */
   fmt.Println("Hello, World!")
}

Vamos dar uma olhada nas várias partes do programa acima -

  • A primeira linha do pacote de programa main define o nome do pacote no qual esse programa deve estar. É uma declaração obrigatória, pois os programas Go são executados em pacotes. O pacote principal é o ponto de partida para executar o programa. Cada pacote possui um caminho e um nome associados a ele.

  • A próxima linha import "fmt" é um comando do pré-processador que diz ao compilador Go para incluir os arquivos contidos no pacote fmt.

  • A próxima linha func main () é a função principal onde a execução do programa começa.

  • A próxima linha /*...*/ é ignorada pelo compilador e está lá para adicionar comentários no programa. Os comentários também são representados usando // semelhantes aos comentários Java ou C ++.

  • A próxima linha fmt.Println (...) é outra função disponível no Go que causa a mensagem "Hello, World!" a ser exibido na tela. Aqui, o pacote fmt exportou o método Println que é usado para exibir a mensagem na tela.

  • Observe o P maiúsculo do método Println. Na linguagem Go, um nome é exportado se começar com letra maiúscula. Exportado significa que a função ou variável / constante está acessível ao importador do respectivo pacote.

Executando um Programa Go

Vamos discutir como salvar o código-fonte em um arquivo, compilá-lo e, finalmente, executar o programa. Siga os passos abaixo -

  • Abra um editor de texto e adicione o código mencionado acima.

  • Salve o arquivo como hello.go

  • Abra o prompt de comando.

  • Vá para o diretório onde você salvou o arquivo.

  • Digite go run hello.go e pressione Enter para executar seu código.

  • Se não houver erros em seu código, você verá "Hello World!" impresso na tela.

$ go run hello.go
Hello, World!

Certifique-se de que o compilador Go esteja em seu caminho e que você o esteja executando no diretório que contém o arquivo de origem hello.go.

Discutimos a estrutura básica de um programa Go no capítulo anterior. Agora será fácil entender os outros blocos de construção básicos da linguagem de programação Go.

Tokens em Go

Um programa Go consiste em vários tokens. Um token é uma palavra-chave, um identificador, uma constante, um literal de string ou um símbolo. Por exemplo, a seguinte instrução Go consiste em seis tokens -

fmt.Println("Hello, World!")

Os tokens individuais são -

fmt
.
Println
(
   "Hello, World!"
)

Separador de Linha

Em um programa Go, a chave separadora de linha é um terminador de instrução. Ou seja, as declarações individuais não precisam de um separador especial como “;” em C. O compilador Go coloca internamente “;” como o terminador da instrução para indicar o fim de uma entidade lógica.

Por exemplo, dê uma olhada nas seguintes declarações -

fmt.Println("Hello, World!")
fmt.Println("I am in Go Programming World!")

Comentários

Os comentários são como textos de ajuda em seu programa Go e são ignorados pelo compilador. Eles começam com / * e terminam com os caracteres * / conforme mostrado abaixo -

/* my first program in Go */

Você não pode ter comentários dentro de comentários e eles não ocorrem em uma string ou em literais de caracteres.

Identificadores

Um identificador Go é um nome usado para identificar uma variável, função ou qualquer outro item definido pelo usuário. Um identificador começa com uma letra de A a Z ou a a z ou um sublinhado _ seguido por zero ou mais letras, sublinhados e dígitos (0 a 9).

identificador = letra {letra | unicode_digit}.

Go não permite caracteres de pontuação como @, $ e% nos identificadores. Go é umcase-sensitivelinguagem de programação. Portanto, Manpower e manpower são dois identificadores diferentes no Go. Aqui estão alguns exemplos de identificadores aceitáveis ​​-

mahesh      kumar   abc   move_name   a_123
myname50   _temp    j      a23b9      retVal

Palavras-chave

A lista a seguir mostra as palavras reservadas em Go. Essas palavras reservadas não podem ser usadas como constantes ou variáveis ​​ou quaisquer outros nomes de identificador.

pausa padrão função interface selecionar
caso adiar Ir mapa Struct
chan outro Vamos para pacote Interruptor
const Cair em E se alcance Tipo
continuar para importar Retorna Var

Espaço em branco em Go

Espaço em branco é o termo usado em Go para descrever espaços em branco, tabulações, caracteres de nova linha e comentários. Uma linha contendo apenas espaços em branco, possivelmente com um comentário, é conhecida como linha em branco e um compilador Go a ignora totalmente.

Espaços em branco separam uma parte de uma instrução de outra e permitem que o compilador identifique onde um elemento em uma instrução, como int, termina e o próximo elemento começa. Portanto, na seguinte declaração -

var age int;

Deve haver pelo menos um caractere de espaço em branco (geralmente um espaço) entre int e age para que o compilador seja capaz de distingui-los. Por outro lado, na seguinte declaração -

fruit = apples + oranges;   // get the total fruit

Nenhum caractere de espaço em branco é necessário entre frutas e =, ou entre = e maçãs, embora você seja livre para incluir alguns se desejar para fins de legibilidade.

Na linguagem de programação Go, os tipos de dados referem-se a um sistema extenso usado para declarar variáveis ​​ou funções de diferentes tipos. O tipo de uma variável determina quanto espaço ela ocupa no armazenamento e como o padrão de bits armazenado é interpretado.

Os tipos em Go podem ser classificados da seguinte forma -

Sr. Não. Tipos e descrição
1

Boolean types

Eles são tipos booleanos e consistem em duas constantes predefinidas: (a) verdadeiro (b) falso

2

Numeric types

Eles são novamente tipos aritméticos e representam a) tipos inteiros ou b) valores de ponto flutuante em todo o programa.

3

String types

Um tipo de string representa o conjunto de valores de string. Seu valor é uma sequência de bytes. Strings são tipos imutáveis ​​que, uma vez criados, não é possível alterar o conteúdo de uma string. O tipo de string pré-declarado é string.

4

Derived types

Eles incluem (a) Tipos de ponteiro, (b) Tipos de matriz, (c) Tipos de estrutura, (d) Tipos de união e (e) Tipos de função f) Tipos de fatia g) Tipos de interface h) Tipos de mapa i) Tipos de canal

Tipos de matriz e tipos de estrutura são referidos coletivamente como aggregate types. O tipo de uma função especifica o conjunto de todas as funções com o mesmo parâmetro e tipos de resultado. Discutiremos os tipos básicos na seção a seguir, enquanto outros tipos serão abordados nos próximos capítulos.

Tipos inteiros

Os tipos inteiros independentes de arquitetura predefinidos são -

Sr. Não. Tipos e descrição
1

uint8

Inteiros de 8 bits sem sinal (0 a 255)

2

uint16

Inteiros de 16 bits sem sinal (0 a 65535)

3

uint32

Inteiros de 32 bits sem sinal (0 a 4294967295)

4

uint64

Inteiros de 64 bits sem sinal (0 a 18446744073709551615)

5

int8

Inteiros de 8 bits com sinal (-128 a 127)

6

int16

Inteiros assinados de 16 bits (-32768 a 32767)

7

int32

Inteiros assinados de 32 bits (-2147483648 a 2147483647)

8

int64

Inteiros de 64 bits assinados (-9223372036854775808 a 9223372036854775807)

Tipos Flutuantes

Os tipos de float independentes de arquitetura predefinidos são -

Sr. Não. Tipos e descrição
1

float32

Números de ponto flutuante IEEE-754 de 32 bits

2

float64

Números de ponto flutuante IEEE-754 de 64 bits

3

complex64

Números complexos com float32 partes reais e imaginárias

4

complex128

Números complexos com partes reais e imaginárias float64

O valor de um número inteiro de n bits é de n bits e é representado usando operações aritméticas de complemento de dois.

Outros Tipos Numéricos

Também há um conjunto de tipos numéricos com tamanhos específicos de implementação -

Sr. Não. Tipos e descrição
1

byte

mesmo que uint8

2

rune

mesmo que int32

3

uint

32 ou 64 bits

4

int

mesmo tamanho que uint

5

uintptr

um inteiro não assinado para armazenar os bits não interpretados de um valor de ponteiro

Uma variável nada mais é do que um nome dado a uma área de armazenamento que os programas podem manipular. Cada variável em Go tem um tipo específico, que determina o tamanho e o layout da memória da variável, a faixa de valores que podem ser armazenados nessa memória e o conjunto de operações que podem ser aplicadas à variável.

O nome de uma variável pode ser composto de letras, dígitos e o caractere de sublinhado. Deve começar com uma letra ou um sublinhado. As letras maiúsculas e minúsculas são diferentes porque Go diferencia maiúsculas de minúsculas. Com base nos tipos básicos explicados no capítulo anterior, haverá os seguintes tipos básicos de variáveis ​​-

Sr. Não Tipo e descrição
1

byte

Normalmente, um único octeto (um byte). Este é um tipo de byte.

2

int

O tamanho mais natural do inteiro para a máquina.

3

float32

Um valor de ponto flutuante de precisão única.

A linguagem de programação Go também permite definir vários outros tipos de variáveis, como Enumeration, Pointer, Array, Structure e Union, que discutiremos nos próximos capítulos. Neste capítulo, enfocaremos apenas os tipos básicos de variáveis.

Definição de Variável em Go

Uma definição de variável informa ao compilador onde e quanto armazenamento criar para a variável. Uma definição de variável especifica um tipo de dados e contém uma lista de uma ou mais variáveis ​​desse tipo da seguinte forma -

var variable_list optional_data_type;

Aqui, optional_data_type é um tipo de dados Go válido, incluindo byte, int, float32, complex64, booleano ou qualquer objeto definido pelo usuário, etc., e variable_listpode consistir em um ou mais nomes de identificadores separados por vírgulas. Algumas declarações válidas são mostradas aqui -

var  i, j, k int;
var  c, ch byte;
var  f, salary float32;
d =  42;

A declaração “var i, j, k;”declara e define as variáveis ​​i, j e k; que instrui o compilador a criar variáveis ​​chamadas i, j e k do tipo int.

As variáveis ​​podem ser inicializadas (atribuídas a um valor inicial) em sua declaração. O tipo de variável é julgado automaticamente pelo compilador com base no valor passado a ela. O inicializador consiste em um sinal de igual seguido por uma expressão constante da seguinte maneira -

variable_name = value;

Por exemplo,

d = 3, f = 5;    // declaration of d and f. Here d and f are int

Para definição sem um inicializador: variáveis ​​com duração de armazenamento estático são inicializadas implicitamente com nil (todos os bytes têm o valor 0); o valor inicial de todas as outras variáveis ​​é o valor zero de seu tipo de dados.

Declaração de tipo estático em Go

Uma declaração de variável de tipo estático fornece garantia ao compilador de que há uma variável disponível com o tipo e nome fornecidos para que o compilador possa prosseguir para a compilação posterior sem exigir os detalhes completos da variável. Uma declaração de variável tem seu significado apenas no momento da compilação, o compilador precisa da declaração da variável real no momento da vinculação do programa.

Exemplo

Tente o exemplo a seguir, onde a variável foi declarada com um tipo e inicializada dentro da função principal -

package main

import "fmt"

func main() {
   var x float64
   x = 20.0
   fmt.Println(x)
   fmt.Printf("x is of type %T\n", x)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

20
x is of type float64

Declaração de tipo dinâmico / inferência de tipo em Go

Uma declaração de variável de tipo dinâmico requer que o compilador interprete o tipo da variável com base no valor passado a ela. O compilador não exige que uma variável tenha um tipo estaticamente como um requisito necessário.

Exemplo

Tente o exemplo a seguir, onde as variáveis ​​foram declaradas sem nenhum tipo. Observe, no caso de inferência de tipo, inicializamos a variávely com: = operador, enquanto x é inicializado usando o operador =.

package main

import "fmt"

func main() {
   var x float64 = 20.0

   y := 42 
   fmt.Println(x)
   fmt.Println(y)
   fmt.Printf("x is of type %T\n", x)
   fmt.Printf("y is of type %T\n", y)	
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

20
42
x is of type float64
y is of type int

Declaração de Variável Mista em Go

Variáveis ​​de diferentes tipos podem ser declaradas de uma só vez usando a inferência de tipo.

Exemplo

package main

import "fmt"

func main() {
   var a, b, c = 3, 4, "foo"  
	
   fmt.Println(a)
   fmt.Println(b)
   fmt.Println(c)
   fmt.Printf("a is of type %T\n", a)
   fmt.Printf("b is of type %T\n", b)
   fmt.Printf("c is of type %T\n", c)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

3
4
foo
a is of type int
b is of type int
c is of type string

Os lvalues ​​e os rvalues ​​em Go

Existem dois tipos de expressões em Go -

  • lvalue- As expressões que se referem a um local da memória são chamadas de expressão "lvalue". Um lvalue pode aparecer como o lado esquerdo ou direito de uma atribuição.

  • rvalue- O termo rvalue se refere a um valor de dados que é armazenado em algum endereço da memória. Um rvalue é uma expressão que não pode ter um valor atribuído a ela, o que significa que um rvalue pode aparecer no lado direito, mas não no lado esquerdo de uma atribuição.

As variáveis ​​são lvalues ​​e, portanto, podem aparecer no lado esquerdo de uma atribuição. Literais numéricos são rvalues ​​e, portanto, não podem ser atribuídos e não podem aparecer no lado esquerdo.

A seguinte declaração é válida -

x = 20.0

A seguinte declaração não é válida. Isso geraria um erro em tempo de compilação -

10 = 20

Constantes referem-se a valores fixos que o programa não pode alterar durante sua execução. Esses valores fixos também são chamadosliterals.

As constantes podem ser de qualquer um dos tipos básicos de dados, como uma constante inteira, uma constante flutuante, uma constante de caractere ou um literal de string . Também existem constantes de enumeração.

As constantes são tratadas como variáveis ​​regulares, exceto que seus valores não podem ser modificados após sua definição.

Literais inteiros

Um literal inteiro pode ser uma constante decimal, octal ou hexadecimal. Um prefixo especifica a base ou raiz: 0x ou 0X para hexadecimal, 0 para octal e nada para decimal.

Um literal inteiro também pode ter um sufixo que é uma combinação de U e L, para sem sinal e longo, respectivamente. O sufixo pode ser maiúsculo ou minúsculo e pode estar em qualquer ordem.

Aqui estão alguns exemplos de literais inteiros -

212         /* Legal */
215u        /* Legal */
0xFeeL      /* Legal */
078         /* Illegal: 8 is not an octal digit */
032UU       /* Illegal: cannot repeat a suffix */

A seguir estão outros exemplos de vários tipos de literais inteiros -

85         /* decimal */
0213       /* octal */
0x4b       /* hexadecimal */
30         /* int */
30u        /* unsigned int */
30l        /* long */
30ul       /* unsigned long */

Literais de ponto flutuante

Um literal de ponto flutuante possui uma parte inteira, um ponto decimal, uma parte fracionária e uma parte expoente. Você pode representar literais de ponto flutuante na forma decimal ou exponencial.

Ao representar usando a forma decimal, você deve incluir a vírgula decimal, o expoente ou ambos e, ao representar usando a forma exponencial, você deve incluir a parte inteira, a parte fracionária ou ambas. O expoente assinado é introduzido por e ou E.

Aqui estão alguns exemplos de literais de ponto flutuante -

3.14159       /* Legal */
314159E-5L    /* Legal */
510E          /* Illegal: incomplete exponent */
210f          /* Illegal: no decimal or exponent */
.e55          /* Illegal: missing integer or fraction */

Sequência de fuga

Quando certos caracteres são precedidos por uma barra invertida, eles terão um significado especial em Go. Eles são conhecidos como códigos de sequência de escape, que são usados ​​para representar nova linha (\ n), tab (\ t), backspace, etc. Aqui, você tem uma lista de alguns desses códigos de sequência de escape -

Sequência de fuga Significado
\\ \ personagem
\ ' ' personagem
\ " " personagem
\? ? personagem
\uma Alerta ou sino
\ b Backspace
\ f Feed de formulário
\ n Nova linha
\ r Retorno de carruagem
\ t Aba horizontal
\ v Aba vertical
\ ooo Número octal de um a três dígitos
\ xhh. . . Número hexadecimal de um ou mais dígitos

O exemplo a seguir mostra como usar \t em um programa -

package main

import "fmt"

func main() {
   fmt.Printf("Hello\tWorld!")
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Hello World!

Literais de string em Go

Literais ou constantes de string são colocados entre aspas duplas "". Uma string contém caracteres semelhantes aos literais de caracteres: caracteres simples, sequências de escape e caracteres universais.

Você pode quebrar uma linha longa em várias linhas usando literais de string e separando-as usando espaços em branco.

Aqui estão alguns exemplos de literais de string. Todas as três formas são strings idênticas.

"hello, dear"

"hello, \

dear"

"hello, " "d" "ear"

A palavra- chave const

Você pode usar const prefixo para declarar constantes com um tipo específico da seguinte forma -

const variable type = value;

O exemplo a seguir mostra como usar o const palavra-chave -

package main

import "fmt"

func main() {
   const LENGTH int = 10
   const WIDTH int = 5   
   var area int

   area = LENGTH * WIDTH
   fmt.Printf("value of area : %d", area)   
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

value of area : 50

Observe que é uma boa prática de programação definir constantes em MAIÚSCULAS.

Um operador é um símbolo que informa ao compilador para executar manipulações matemáticas ou lógicas específicas. A linguagem Go é rica em operadores integrados e fornece os seguintes tipos de operadores -

  • Operadores aritméticos
  • Operadores Relacionais
  • Operadores lógicos
  • Operadores bit a bit
  • Operadores de atribuição
  • Operadores diversos

Este tutorial explica os operadores aritméticos, relacionais, lógicos, bit a bit, atribuição e outros, um por um.

Operadores aritméticos

A tabela a seguir mostra todos os operadores aritméticos suportados pela linguagem Go. Assumir variávelA contém 10 e variável B detém 20 então -

Mostrar exemplos

Operador Descrição Exemplo
+ Adiciona dois operandos A + B dá 30
- Subtrai o segundo operando do primeiro A - B dá -10
* Multiplica ambos os operandos A * B dá 200
/ Divide o numerador pelo denominador. B / A dá 2
% Operador de módulo; dá o resto após uma divisão inteira. B% A dá 0
++ Operador de incremento. Ele aumenta o valor inteiro em um. A ++ dá 11
- Operador de decremento. Ele diminui o valor inteiro em um. A-- dá 9

Operadores Relacionais

A tabela a seguir lista todos os operadores relacionais suportados pela linguagem Go. Assumir variávelA contém 10 e variável B contém 20, então -

Mostrar exemplos

Operador Descrição Exemplo
== Verifica se os valores de dois operandos são iguais ou não; se sim, a condição se torna verdadeira. (A == B) não é verdade.
! = Verifica se os valores de dois operandos são iguais ou não; se os valores não forem iguais, a condição se torna verdadeira. (A! = B) é verdade.
> Verifica se o valor do operando esquerdo é maior que o valor do operando direito; se sim, a condição se torna verdadeira. (A> B) não é verdade.
< Verifica se o valor do operando esquerdo é menor que o valor do operando direito; se sim, a condição se torna verdadeira. (A <B) é verdade.
> = Verifica se o valor do operando esquerdo é maior ou igual ao valor do operando direito; se sim, a condição se torna verdadeira. (A> = B) não é verdade.
<= Verifica se o valor do operando esquerdo é menor ou igual ao valor do operando direito; se sim, a condição se torna verdadeira. (A <= B) é verdadeiro.

Operadores lógicos

A tabela a seguir lista todos os operadores lógicos suportados pela linguagem Go. Assumir variávelA detém 1 e variável B segura 0, então -

Mostrar exemplos

Operador Descrição Exemplo
&& Operador lógico chamado AND. Se ambos os operandos forem diferentes de zero, a condição se torna verdadeira. (A && B) é falso.
|| Operador lógico ou chamado. Se qualquer um dos dois operandos for diferente de zero, a condição se torna verdadeira. (A || B) é verdade.
! Operador lógico chamado NOT. Use para reverter o estado lógico de seu operando. Se uma condição for verdadeira, o operador NOT lógico tornará falso. ! (A && B) é verdade.

A tabela a seguir mostra todos os operadores lógicos suportados pela linguagem Go. Assumir variávelA é verdadeiro e variável B é falso, então -

Operador Descrição Exemplo
&& Operador lógico chamado AND. Se ambos os operandos forem falsos, a condição se tornará falsa. (A && B) é falso.
|| Operador lógico ou chamado. Se qualquer um dos dois operandos for verdadeiro, a condição se tornará verdadeira. (A || B) é verdade.
! Operador lógico chamado NOT. Use para reverter o estado lógico de seu operando. Se uma condição for verdadeira, o operador lógico NOT a tornará falsa. ! (A && B) é verdade.

Operadores bit a bit

Operadores bit a bit trabalham em bits e executam operações bit a bit. As tabelas de verdade para &, | e ^ são as seguintes -

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

Suponha que A = 60; e B = 13. No formato binário, eles serão os seguintes -

A = 0011 1100

B = 0000 1101

-----------------

A&B = 0000 1100

A | B = 0011 1101

A ^ B = 0011 0001

~ A = 1100 0011

Os operadores bit a bit suportados pela linguagem C estão listados na tabela a seguir. Suponha que a variável A tenha 60 e a variável B tenha 13, então -

Mostrar exemplos

Operador Descrição Exemplo
E O operador Binário AND copia um bit para o resultado se ele existir em ambos os operandos. (A e B) dará 12, que é 0000 1100
| O operador binário OR copia um bit se ele existir em qualquer operando. (A | B) dará 61, que é 0011 1101
^ O operador binário XOR copia o bit se estiver definido em um operando, mas não em ambos. (A ^ B) dará 49, que é 0011 0001
<< Operador binário de deslocamento à esquerda. O valor dos operandos à esquerda é movido para a esquerda pelo número de bits especificado pelo operando à direita. Um << 2 dará 240, que é 1111 0000
>> Operador binário de deslocamento à direita. O valor dos operandos à esquerda é movido para a direita pelo número de bits especificado pelo operando à direita. Um >> 2 dará 15, que é 0000 1111

Operadores de atribuição

A tabela a seguir lista todos os operadores de atribuição suportados pela linguagem Go -

Mostrar exemplos

Operador Descrição Exemplo
= Operador de atribuição simples, atribui valores de operandos do lado direito para operando do lado esquerdo C = A + B irá atribuir o valor de A + B em C
+ = Adicionar operador de atribuição AND, adiciona o operando direito ao operando esquerdo e atribui o resultado ao operando esquerdo C + = A é equivalente a C = C + A
- = Subtrai o operador de atribuição AND, subtrai o operando direito do operando esquerdo e atribui o resultado ao operando esquerdo C - = A é equivalente a C = C - A
* = Multiplicar E operador de atribuição, multiplica o operando direito com o operando esquerdo e atribui o resultado ao operando esquerdo C * = A é equivalente a C = C * A
/ = Operador de atribuição e divisão, divide o operando esquerdo com o operando direito e atribui o resultado ao operando esquerdo C / = A é equivalente a C = C / A
% = Módulo E operador de atribuição, leva o módulo usando dois operandos e atribui o resultado ao operando esquerdo C% = A é equivalente a C = C% A
<< = Deslocamento à esquerda E operador de atribuição C << = 2 é igual a C = C << 2
>> = Deslocamento à direita E operador de atribuição C >> = 2 é igual a C = C >> 2
& = Operador de atribuição AND bit a bit C & = 2 é igual a C = C & 2
^ = OR exclusivo bit a bit e operador de atribuição C ^ = 2 é igual a C = C ^ 2
| = OR inclusivo bit a bit e operador de atribuição C | = 2 é igual a C = C | 2

Operadores diversos

Existem alguns outros operadores importantes suportados pelo Go Language, incluindo sizeof e ?:.

Mostrar exemplos

Operador Descrição Exemplo
E Retorna o endereço de uma variável. &uma; fornece o endereço real da variável.
* Ponteiro para uma variável. *uma; fornece um ponteiro para uma variável.

Precedência de operadores em Go

A precedência do operador determina o agrupamento de termos em uma expressão. Isso afeta como uma expressão é avaliada. Certos operadores têm precedência mais alta do que outros; por exemplo, o operador de multiplicação tem precedência mais alta do que o operador de adição.

Por exemplo x = 7 + 3 * 2; aqui, x é atribuído a 13, não 20, porque o operador * tem precedência mais alta do que +, portanto, primeiro é multiplicado por 3 * 2 e, em seguida, é adicionado a 7.

Aqui, os operadores com a precedência mais alta aparecem na parte superior da tabela, aqueles com a mais baixa aparecem na parte inferior. Em uma expressão, os operadores de precedência superior serão avaliados primeiro.

Mostrar exemplos

Categoria Operador Associatividade
Postfix () [] ->. ++ - - Da esquerda para direita
Unário + -! ~ ++ - - (tipo) * & sizeof Direita para esquerda
Multiplicativo * /% Da esquerda para direita
Aditivo + - Da esquerda para direita
Mudança << >> Da esquerda para direita
Relacional <<=>> = Da esquerda para direita
Igualdade ==! = Da esquerda para direita
E bit a bit E Da esquerda para direita
XOR bit a bit ^ Da esquerda para direita
OR bit a bit | Da esquerda para direita
E lógico && Da esquerda para direita
OR lógico || Da esquerda para direita
Tarefa = + = - = * = / =% = >> = << = & = ^ = | = Direita para esquerda
Vírgula , Da esquerda para direita

As estruturas de tomada de decisão requerem que o programador especifique uma ou mais condições a serem avaliadas ou testadas pelo programa, junto com uma instrução ou instruções a serem executadas se a condição for determinada como verdadeira e, opcionalmente, outras instruções a serem executadas se a condição está determinado a ser falso.

A seguir está a forma geral de uma estrutura típica de tomada de decisão encontrada na maioria das linguagens de programação -

A linguagem de programação Go fornece os seguintes tipos de declarações de tomada de decisão. Clique nos links a seguir para verificar seus detalhes.

Sr. Não Declaração e descrição
1 declaração if

A if statement consiste em uma expressão booleana seguida por uma ou mais instruções.

2 declaração if ... else

A if statement pode ser seguido por um opcional else statement, que é executado quando a expressão booleana é falsa.

3 declarações if aninhadas

Você pode usar um if ou else if declaração dentro de outra if ou else if afirmações).

4 declaração switch

UMA switch instrução permite que uma variável seja testada quanto à igualdade em relação a uma lista de valores.

5 selecione a declaração

UMA select declaração é semelhante a switch declaração com diferença que as declarações de caso se referem a comunicações de canal.

Pode haver uma situação em que você precise executar um bloco de código várias vezes. Em geral, as instruções são executadas sequencialmente: a primeira instrução em uma função é executada primeiro, seguida pela segunda e assim por diante.

As linguagens de programação fornecem várias estruturas de controle que permitem caminhos de execução mais complicados.

Uma instrução de loop nos permite executar uma instrução ou grupo de instruções várias vezes e a seguir está a forma geral de uma instrução de loop na maioria das linguagens de programação -

A linguagem de programação Go fornece os seguintes tipos de loop para lidar com os requisitos de loop.

Sr. Não Tipo de Loop e Descrição
1 para loop

Ele executa uma sequência de instruções várias vezes e abrevia o código que gerencia a variável de loop.

2 loops aninhados

Estes são um ou vários loops dentro de qualquer loop for.

Declarações de controle de loop

As instruções de controle de loop alteram uma execução de sua sequência normal. Quando uma execução sai de seu escopo, todos os objetos automáticos criados naquele escopo são destruídos.

Go suporta as seguintes instruções de controle -

Sr. Não Declaração de controle e descrição
1 declaração de quebra

Termina um for loop ou switch instrução e transfere a execução para a instrução imediatamente após o loop for ou switch.

2 continuar declaração

Isso faz com que o loop pule o restante de seu corpo e teste novamente sua condição antes de ser reiterado.

3 declaração goto

Ele transfere o controle para a instrução rotulada.

The Infinite Loop

A loop becomes an infinite loop if its condition never becomes false. The for loop is traditionally used for this purpose. Since none of the three expressions that form the for loop are required, you can make an endless loop by leaving the conditional expression empty or by passing true to it.

package main

import "fmt"

func main() {
   for true  {
       fmt.Printf("This loop will run forever.\n");
   }
}

When the conditional expression is absent, it is assumed to be true. You may have an initialization and increment expression, but C programmers more commonly use the for(;;) construct to signify an infinite loop.

Note − You can terminate an infinite loop by pressing Ctrl + C keys.

A function is a group of statements that together perform a task. Every Go program has at least one function, which is main(). You can divide your code into separate functions. How you divide your code among different functions is up to you, but logically, the division should be such that each function performs a specific task.

A function declaration tells the compiler about a function name, return type, and parameters. A function definition provides the actual body of the function.

The Go standard library provides numerous built-in functions that your program can call. For example, the function len() takes arguments of various types and returns the length of the type. If a string is passed to it, the function returns the length of the string in bytes. If an array is passed to it, the function returns the length of the array.

Functions are also known as method, sub-routine, or procedure.

Defining a Function

The general form of a function definition in Go programming language is as follows −

func function_name( [parameter list] ) [return_types]
{
   body of the function
}

A function definition in Go programming language consists of a function header and a function body. Here are all the parts of a function −

  • Func − It starts the declaration of a function.

  • Function Name − It is the actual name of the function. The function name and the parameter list together constitute the function signature.

  • Parameters − A parameter is like a placeholder. When a function is invoked, you pass a value to the parameter. This value is referred to as actual parameter or argument. The parameter list refers to the type, order, and number of the parameters of a function. Parameters are optional; that is, a function may contain no parameters.

  • Return Type − A function may return a list of values. The return_types is the list of data types of the values the function returns. Some functions perform the desired operations without returning a value. In this case, the return_type is the not required.

  • Function Body − It contains a collection of statements that define what the function does.

Example

The following source code shows a function called max(). This function takes two parameters num1 and num2 and returns the maximum between the two −

/* function returning the max between two numbers */
func max(num1, num2 int) int {
   /* local variable declaration */
   result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}

Calling a Function

While creating a Go function, you give a definition of what the function has to do. To use a function, you will have to call that function to perform the defined task.

When a program calls a function, the program control is transferred to the called function. A called function performs a defined task and when its return statement is executed or when its function-ending closing brace is reached, it returns the program control back to the main program.

To call a function, you simply need to pass the required parameters along with its function name. If the function returns a value, then you can store the returned value. For example −

package main

import "fmt"

func main() {
   /* local variable definition */
   var a int = 100
   var b int = 200
   var ret int

   /* calling a function to get max value */
   ret = max(a, b)

   fmt.Printf( "Max value is : %d\n", ret )
}

/* function returning the max between two numbers */
func max(num1, num2 int) int {
   /* local variable declaration */
   var result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}

We have kept the max() function along with the main() function and compiled the source code. While running the final executable, it would produce the following result −

Max value is : 200

Returning multiple values from Function

A Go function can return multiple values. For example −

package main

import "fmt"

func swap(x, y string) (string, string) {
   return y, x
}
func main() {
   a, b := swap("Mahesh", "Kumar")
   fmt.Println(a, b)
}

When the above code is compiled and executed, it produces the following result −

Kumar Mahesh

Function Arguments

If a function is to use arguments, it must declare variables that accept the values of the arguments. These variables are called the formal parameters of the function.

The formal parameters behave like other local variables inside the function and are created upon entry into the function and destroyed upon exit.

While calling a function, there are two ways that arguments can be passed to a function −

Sr.No Call Type & Description
1 Call by value

This method copies the actual value of an argument into the formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument.

2 Call by reference

This method copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. This means that changes made to the parameter affect the argument.

By default, Go uses call by value to pass arguments. In general, it means the code within a function cannot alter the arguments used to call the function. The above program, while calling the max() function, used the same method.

Function Usage

A function can be used in the following ways:

Sr.No Function Usage & Description
1 Function as Value

Functions can be created on the fly and can be used as values.

2 Function Closures

Functions closures are anonymous functions and can be used in dynamic programming.

3 Method

Methods are special functions with a receiver.

A scope in any programming is a region of the program where a defined variable can exist and beyond that the variable cannot be accessed. There are three places where variables can be declared in Go programming language −

  • Inside a function or a block (local variables)

  • Outside of all functions (global variables)

  • In the definition of function parameters (formal parameters)

Let us find out what are local and global variables and what are formal parameters.

Local Variables

Variables that are declared inside a function or a block are called local variables. They can be used only by statements that are inside that function or block of code. Local variables are not known to functions outside their own. The following example uses local variables. Here all the variables a, b, and c are local to the main() function.

package main

import "fmt"

func main() {
   /* local variable declaration */
   var a, b, c int 

   /* actual initialization */
   a = 10
   b = 20
   c = a + b

   fmt.Printf ("value of a = %d, b = %d and c = %d\n", a, b, c)
}

When the above code is compiled and executed, it produces the following result −

value of a = 10, b = 20 and c = 30

Variáveis ​​globais

Variáveis ​​globais são definidas fora de uma função, geralmente no topo do programa. As variáveis ​​globais mantêm seu valor durante todo o tempo de vida do programa e podem ser acessadas dentro de qualquer uma das funções definidas para o programa.

Uma variável global pode ser acessada por qualquer função. Ou seja, uma variável global está disponível para uso em todo o programa após sua declaração. O exemplo a seguir usa variáveis ​​globais e locais -

package main

import "fmt"
 
/* global variable declaration */
var g int
 
func main() {
   /* local variable declaration */
   var a, b int

   /* actual initialization */
   a = 10
   b = 20
   g = a + b

   fmt.Printf("value of a = %d, b = %d and g = %d\n", a, b, g)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

value of a = 10, b = 20 and g = 30

Um programa pode ter o mesmo nome para variáveis ​​locais e globais, mas o valor da variável local dentro de uma função tem preferência. Por exemplo -

package main

import "fmt"
 
/* global variable declaration */
var g int = 20
 
func main() {
   /* local variable declaration */
   var g int = 10
 
   fmt.Printf ("value of g = %d\n",  g)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

value of g = 10

Parâmetros Formais

Parâmetros formais são tratados como variáveis ​​locais dentro dessa função e têm preferência sobre as variáveis ​​globais. Por exemplo -

package main

import "fmt"
 
/* global variable declaration */
var a int = 20;
 
func main() {
   /* local variable declaration in main function */
   var a int = 10
   var b int = 20
   var c int = 0

   fmt.Printf("value of a in main() = %d\n",  a);
   c = sum( a, b);
   fmt.Printf("value of c in main() = %d\n",  c);
}
/* function to add two integers */
func sum(a, b int) int {
   fmt.Printf("value of a in sum() = %d\n",  a);
   fmt.Printf("value of b in sum() = %d\n",  b);

   return a + b;
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

value of a in main() = 10
value of a in sum() = 10
value of b in sum() = 20
value of c in main() = 30

Inicializando Variáveis ​​Locais e Globais

As variáveis ​​locais e globais são inicializadas com seu valor padrão, que é 0; enquanto os ponteiros são inicializados com nil.

Tipo de dados Valor inicial padrão
int 0
float32 0
ponteiro nada

Strings, amplamente utilizadas na programação Go, são uma fatia de bytes somente leitura. Na linguagem de programação Go, as strings sãoslices. A plataforma Go fornece várias bibliotecas para manipular strings.

  • unicode
  • regexp
  • strings

Criando Strings

A maneira mais direta de criar uma string é escrever -

var greeting = "Hello world!"

Sempre que encontra um literal de string em seu código, o compilador cria um objeto de string com seu valor neste caso, "Olá, mundo! '.

Um literal de string contém sequências UTF-8 válidas chamadas runas. Uma String contém bytes arbitrários.

package main

import "fmt"

func main() {
   var greeting =  "Hello world!"
   
   fmt.Printf("normal string: ")
   fmt.Printf("%s", greeting)
   fmt.Printf("\n")
   fmt.Printf("hex bytes: ")
   
   for i := 0; i < len(greeting); i++ {
       fmt.Printf("%x ", greeting[i])
   }
   fmt.Printf("\n")
   
   const sampleText = "\xbd\xb2\x3d\xbc\x20\xe2\x8c\x98" 
   /*q flag escapes unprintable characters, with + flag it escapses non-ascii 
   characters as well to make output unambigous  
   */
   fmt.Printf("quoted string: ")
   fmt.Printf("%+q", sampleText)
   fmt.Printf("\n")  
}

Isso produziria o seguinte resultado -

normal string: Hello world!
hex bytes: 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 
quoted string: "\xbd\xb2=\xbc \u2318"

Note - O literal de string é imutável, de modo que, uma vez criado, um literal de string não pode ser alterado.

Comprimento da corda

O método len (str) retorna o número de bytes contidos no literal de string.

package main

import "fmt"

func main() {
   var greeting =  "Hello world!"
   
   fmt.Printf("String Length is: ")
   fmt.Println(len(greeting))  
}

Isso produziria o seguinte resultado -

String Length is : 12

Strings de concatenação

O pacote de strings inclui um método join para concatenar várias strings -

strings.Join(sample, " ")

Join concatena os elementos de uma matriz para criar uma única string. O segundo parâmetro é o separador que é colocado entre o elemento da matriz.

Vejamos o seguinte exemplo -

package main

import ("fmt" "math" )"fmt" "strings")

func main() {
   greetings :=  []string{"Hello","world!"}   
   fmt.Println(strings.Join(greetings, " "))
}

Isso produziria o seguinte resultado -

Hello world!

A linguagem de programação Go fornece uma estrutura de dados chamada the array, que pode armazenar uma coleção sequencial de tamanho fixo de elementos do mesmo tipo. Uma matriz é usada para armazenar uma coleção de dados, mas geralmente é mais útil pensar em uma matriz como uma coleção de variáveis ​​do mesmo tipo.

Em vez de declarar variáveis ​​individuais, como número0, número1, ... e número99, você declara uma variável de matriz, como números e usa números [0], números [1] e ..., números [99] para representar variáveis ​​individuais. Um elemento específico em uma matriz é acessado por um índice.

Todos os arrays consistem em locais de memória contíguos. O endereço mais baixo corresponde ao primeiro elemento e o endereço mais alto ao último elemento.

Declaração de matrizes

Para declarar uma matriz em Go, um programador especifica o tipo dos elementos e o número de elementos exigidos por uma matriz da seguinte maneira -

var variable_name [SIZE] variable_type

Isso é chamado de matriz unidimensional . oarraySize deve ser uma constante inteira maior que zero e typepode ser qualquer tipo de dados Go válido. Por exemplo, para declarar uma matriz de 10 elementos chamadabalance do tipo float32, use esta instrução -

var balance [10] float32

Aqui, balance é uma matriz variável que pode conter até 10 números flutuantes.

Inicializando matrizes

Você pode inicializar o array em Go um por um ou usando uma única instrução da seguinte maneira -

var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

O número de valores entre colchetes {} não pode ser maior do que o número de elementos que declaramos para a matriz entre colchetes [].

Se você omitir o tamanho do array, um array grande o suficiente para conter a inicialização é criado. Portanto, se você escrever -

var balance = []float32{1000.0, 2.0, 3.4, 7.0, 50.0}

Você criará exatamente a mesma matriz que fez no exemplo anterior. A seguir está um exemplo para atribuir um único elemento da matriz -

balance[4] = 50.0

O acima cessionários instrução número elemento 5 th na matriz com um valor de 50,0. Todas as matrizes têm 0 como o índice de seu primeiro elemento, que também é chamado de índice de base e o último índice de uma matriz terá o tamanho total da matriz menos 1. A seguir está a representação pictórica da mesma matriz que discutimos acima -

Acessando Elementos de Matriz

Um elemento é acessado indexando o nome da matriz. Isso é feito colocando o índice do elemento entre colchetes após o nome da matriz. Por exemplo -

float32 salary = balance[9]

A declaração acima levará 10 th elemento da matriz e atribuir o valor a variável salário. A seguir está um exemplo que usará todos os três conceitos acima mencionados viz. declaração, atribuição e acesso a matrizes -

package main

import "fmt"

func main() {
   var n [10]int /* n is an array of 10 integers */
   var i,j int

   /* initialize elements of array n to 0 */         
   for i = 0; i < 10; i++ {
      n[i] = i + 100 /* set element at location i to i + 100 */
   }
   /* output each array element's value */
   for j = 0; j < 10; j++ {
      fmt.Printf("Element[%d] = %d\n", j, n[j] )
   }
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

Go Arrays em detalhes

Existem conceitos importantes relacionados a array que devem ser claros para um programador Go -

Sr. Não Conceito e descrição
1 Matrizes multidimensionais

Go oferece suporte a matrizes multidimensionais. A forma mais simples de uma matriz multidimensional é a matriz bidimensional.

2 Passando matrizes para funções

Você pode passar para a função um ponteiro para uma matriz, especificando o nome da matriz sem um índice.

Os ponteiros do Go são fáceis e divertidos de aprender. Algumas tarefas de programação Go são realizadas mais facilmente com ponteiros, e outras tarefas, como chamada por referência, não podem ser executadas sem o uso de ponteiros. Portanto, torna-se necessário aprender dicas para se tornar um programador Go perfeito.

Como você sabe, cada variável é um local da memória e cada local da memória tem seu endereço definido, que pode ser acessado usando o operador E comercial (&), que denota um endereço na memória. Considere o seguinte exemplo, que imprimirá o endereço das variáveis ​​definidas -

package main

import "fmt"

func main() {
   var a int = 10   
   fmt.Printf("Address of a variable: %x\n", &a  )
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Address of a variable: 10328000

Então você entendeu o que é endereço de memória e como acessá-lo. Agora vamos ver o que são os ponteiros.

O que são ponteiros?

UMA pointeré uma variável cujo valor é o endereço de outra variável, ou seja, o endereço direto do local da memória. Como qualquer variável ou constante, você deve declarar um ponteiro antes de usá-lo para armazenar qualquer endereço de variável. A forma geral de uma declaração de variável de ponteiro é -

var var_name *var-type

Aqui, typeé o tipo base do ponteiro; deve ser um tipo de dados C válido evar-nameé o nome da variável de ponteiro. O asterisco * que você usou para declarar um ponteiro é o mesmo asterisco que você usa para a multiplicação. No entanto, nesta declaração, o asterisco está sendo usado para designar uma variável como um ponteiro. A seguir estão as declarações de ponteiro válidas -

var ip *int        /* pointer to an integer */
var fp *float32    /* pointer to a float */

O tipo de dados real do valor de todos os ponteiros, seja inteiro, flutuante ou outro, é o mesmo, um número hexadecimal longo que representa um endereço de memória. A única diferença entre ponteiros de diferentes tipos de dados é o tipo de dados da variável ou constante para a qual o ponteiro aponta.

Como usar ponteiros?

Existem algumas operações importantes, que frequentemente realizamos com ponteiros: (a) definimos variáveis ​​de ponteiro, (b) atribuímos o endereço de uma variável a um ponteiro e (c) acessamos o valor no endereço armazenado na variável de ponteiro .

Todas essas operações são realizadas utilizando o operador unário * que retorna o valor da variável localizada no endereço especificado por seu operando. O exemplo a seguir demonstra como realizar essas operações -

package main

import "fmt"

func main() {
   var a int = 20   /* actual variable declaration */
   var ip *int      /* pointer variable declaration */

   ip = &a  /* store address of a in pointer variable*/

   fmt.Printf("Address of a variable: %x\n", &a  )

   /* address stored in pointer variable */
   fmt.Printf("Address stored in ip variable: %x\n", ip )

   /* access the value using the pointer */
   fmt.Printf("Value of *ip variable: %d\n", *ip )
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Address of var variable: 10328000
Address stored in ip variable: 10328000
Value of *ip variable: 20

Pontos nulos em Go

O compilador Go atribui um valor Nil a uma variável de ponteiro caso você não tenha o endereço exato a ser atribuído. Isso é feito no momento da declaração da variável. Um ponteiro que é atribuído nil é chamado denil ponteiro.

O ponteiro nil é uma constante com valor zero definido em várias bibliotecas padrão. Considere o seguinte programa -

package main

import "fmt"

func main() {
   var  ptr *int

   fmt.Printf("The value of ptr is : %x\n", ptr  )
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

The value of ptr is 0

Na maioria dos sistemas operacionais, os programas não têm permissão para acessar a memória no endereço 0 porque essa memória é reservada pelo sistema operacional. No entanto, o endereço de memória 0 tem um significado especial; ele sinaliza que o ponteiro não se destina a apontar para um local de memória acessível. Mas, por convenção, se um ponteiro contém o valor nil (zero), presume-se que ele não aponte para nada.

Para verificar se há um ponteiro nulo, você pode usar uma instrução if da seguinte maneira -

if(ptr != nil)     /* succeeds if p is not nil */
if(ptr == nil)    /* succeeds if p is null */

Ponteiros Go em detalhes

Os ponteiros têm muitos conceitos, mas fáceis, e são muito importantes para a programação Go. Os seguintes conceitos de ponteiros devem ser claros para um programador Go -

Sr. Não Conceito e descrição
1 Go - matriz de ponteiros

Você pode definir matrizes para conter uma série de ponteiros.

2 Go - Ponteiro para ponteiro

Go permite que você tenha um ponteiro sobre um ponteiro e assim por diante.

3 Passando ponteiros para funções no Go

Passar um argumento por referência ou por endereço permite que o argumento passado seja alterado na função de chamada pela função chamada.

Os arrays Go permitem definir variáveis ​​que podem conter vários itens de dados do mesmo tipo. Structure é outro tipo de dados definido pelo usuário disponível na programação Go, que permite combinar itens de dados de diferentes tipos.

As estruturas são usadas para representar um registro. Suponha que você queira controlar os livros de uma biblioteca. Você pode querer rastrear os seguintes atributos de cada livro -

  • Title
  • Author
  • Subject
  • ID do livro

Nesse cenário, as estruturas são altamente úteis.

Definindo uma Estrutura

Para definir uma estrutura, você deve usar type e structafirmações. A instrução struct define um novo tipo de dados, com vários membros para seu programa. A instrução type associa um nome ao tipo que é struct em nosso caso. O formato da instrução de estrutura é o seguinte -

type struct_variable_type struct {
   member definition;
   member definition;
   ...
   member definition;
}

Depois que um tipo de estrutura é definido, ele pode ser usado para declarar variáveis ​​desse tipo usando a seguinte sintaxe.

variable_name := structure_variable_type {value1, value2...valuen}

Acessando membros da estrutura

Para acessar qualquer membro de uma estrutura, usamos o member access operator (.).O operador de acesso de membro é codificado como um período entre o nome da variável de estrutura e o membro da estrutura que desejamos acessar. Você usariastructpalavra-chave para definir variáveis ​​do tipo de estrutura. O exemplo a seguir explica como usar uma estrutura -

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}
func main() {
   var Book1 Books    /* Declare Book1 of type Book */
   var Book2 Books    /* Declare Book2 of type Book */
 
   /* book 1 specification */
   Book1.title = "Go Programming"
   Book1.author = "Mahesh Kumar"
   Book1.subject = "Go Programming Tutorial"
   Book1.book_id = 6495407

   /* book 2 specification */
   Book2.title = "Telecom Billing"
   Book2.author = "Zara Ali"
   Book2.subject = "Telecom Billing Tutorial"
   Book2.book_id = 6495700
 
   /* print Book1 info */
   fmt.Printf( "Book 1 title : %s\n", Book1.title)
   fmt.Printf( "Book 1 author : %s\n", Book1.author)
   fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
   fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)

   /* print Book2 info */
   fmt.Printf( "Book 2 title : %s\n", Book2.title)
   fmt.Printf( "Book 2 author : %s\n", Book2.author)
   fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
   fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Book 1 title      : Go Programming
Book 1 author     : Mahesh Kumar
Book 1 subject    : Go Programming Tutorial
Book 1 book_id    : 6495407
Book 2 title      : Telecom Billing
Book 2 author     : Zara Ali
Book 2 subject    : Telecom Billing Tutorial
Book 2 book_id    : 6495700

Estruturas como argumentos de função

Você pode passar uma estrutura como um argumento de função de maneira muito semelhante à que passa qualquer outra variável ou ponteiro. Você acessaria as variáveis ​​de estrutura da mesma forma que fez no exemplo acima -

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}
func main() {
   var Book1 Books    /* Declare Book1 of type Book */
   var Book2 Books    /* Declare Book2 of type Book */
 
   /* book 1 specification */
   Book1.title = "Go Programming"
   Book1.author = "Mahesh Kumar"
   Book1.subject = "Go Programming Tutorial"
   Book1.book_id = 6495407

   /* book 2 specification */
   Book2.title = "Telecom Billing"
   Book2.author = "Zara Ali"
   Book2.subject = "Telecom Billing Tutorial"
   Book2.book_id = 6495700
 
   /* print Book1 info */
   printBook(Book1)

   /* print Book2 info */
   printBook(Book2)
}
func printBook( book Books ) {
   fmt.Printf( "Book title : %s\n", book.title);
   fmt.Printf( "Book author : %s\n", book.author);
   fmt.Printf( "Book subject : %s\n", book.subject);
   fmt.Printf( "Book book_id : %d\n", book.book_id);
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Book title     : Go Programming
Book author    : Mahesh Kumar
Book subject   : Go Programming Tutorial
Book book_id   : 6495407
Book title     : Telecom Billing
Book author    : Zara Ali
Book subject   : Telecom Billing Tutorial
Book book_id   : 6495700

Indicadores para estruturas

Você pode definir ponteiros para estruturas da mesma forma que define ponteiros para qualquer outra variável da seguinte maneira -

var struct_pointer *Books

Agora, você pode armazenar o endereço de uma variável de estrutura na variável de ponteiro definida acima. Para encontrar o endereço de uma variável de estrutura, coloque o operador & antes do nome da estrutura da seguinte maneira -

struct_pointer = &Book1;

Para acessar os membros de uma estrutura usando um ponteiro para essa estrutura, você deve usar o "." operador da seguinte forma -

struct_pointer.title;

Vamos reescrever o exemplo acima usando o ponteiro de estrutura -

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}
func main() {
   var Book1 Books   /* Declare Book1 of type Book */
   var Book2 Books   /* Declare Book2 of type Book */
 
   /* book 1 specification */
   Book1.title = "Go Programming"
   Book1.author = "Mahesh Kumar"
   Book1.subject = "Go Programming Tutorial"
   Book1.book_id = 6495407

   /* book 2 specification */
   Book2.title = "Telecom Billing"
   Book2.author = "Zara Ali"
   Book2.subject = "Telecom Billing Tutorial"
   Book2.book_id = 6495700
 
   /* print Book1 info */
   printBook(&Book1)

   /* print Book2 info */
   printBook(&Book2)
}
func printBook( book *Books ) {
   fmt.Printf( "Book title : %s\n", book.title);
   fmt.Printf( "Book author : %s\n", book.author);
   fmt.Printf( "Book subject : %s\n", book.subject);
   fmt.Printf( "Book book_id : %d\n", book.book_id);
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Book title     : Go Programming
Book author    : Mahesh Kumar
Book subject   : Go Programming Tutorial
Book book_id   : 6495407
Book title     : Telecom Billing
Book author    : Zara Ali
Book subject   : Telecom Billing Tutorial
Book book_id   : 6495700

Go Slice é uma abstração sobre Go Array. Go Array permite definir variáveis ​​que podem conter vários itens de dados do mesmo tipo, mas não fornece nenhum método embutido para aumentar seu tamanho dinamicamente ou obter um sub-array próprio. As fatias superam essa limitação. Ele fornece muitas funções utilitárias exigidas no Array e é amplamente utilizado na programação Go.

Definindo uma fatia

Para definir uma fatia, você pode declará-la como uma matriz sem especificar seu tamanho. Alternativamente, você pode usarmake função para criar uma fatia.

var numbers []int /* a slice of unspecified size */
/* numbers == []int{0,0,0,0,0}*/
numbers = make([]int,5,5) /* a slice of length 5 and capacity 5*/

funções len () e cap ()

Uma fatia é uma abstração sobre um array. Na verdade, ele usa arrays como uma estrutura subjacente. olen() função retorna os elementos presentes na fatia onde cap()função retorna a capacidade da fatia (ou seja, quantos elementos ela pode acomodar). O exemplo a seguir explica o uso de fatia -

package main

import "fmt"

func main() {
   var numbers = make([]int,3,5)
   printSlice(numbers)
}
func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

len = 3 cap = 5 slice = [0 0 0]

Fatia nula

Se uma fatia for declarada sem entradas, por padrão, ela será inicializada como nula. Seu comprimento e capacidade são zero. Por exemplo -

package main

import "fmt"

func main() {
   var numbers []int
   printSlice(numbers)
   
   if(numbers == nil){
      fmt.Printf("slice is nil")
   }
}
func printSlice(x []int){
   fmt.Printf("len = %d cap = %d slice = %v\n", len(x), cap(x),x)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

len = 0 cap = 0 slice = []
slice is nil

Sublicenciando

Slice permite que os limites inferior e superior sejam especificados para obter o subforte dele usando[lower-bound:upper-bound]. Por exemplo -

package main

import "fmt"

func main() {
   /* create a slice */
   numbers := []int{0,1,2,3,4,5,6,7,8}   
   printSlice(numbers)
   
   /* print the original slice */
   fmt.Println("numbers ==", numbers)
   
   /* print the sub slice starting from index 1(included) to index 4(excluded)*/
   fmt.Println("numbers[1:4] ==", numbers[1:4])
   
   /* missing lower bound implies 0*/
   fmt.Println("numbers[:3] ==", numbers[:3])
   
   /* missing upper bound implies len(s)*/
   fmt.Println("numbers[4:] ==", numbers[4:])
   
   numbers1 := make([]int,0,5)
   printSlice(numbers1)
   
   /* print the sub slice starting from index 0(included) to index 2(excluded) */
   number2 := numbers[:2]
   printSlice(number2)
   
   /* print the sub slice starting from index 2(included) to index 5(excluded) */
   number3 := numbers[2:5]
   printSlice(number3)
   
}
func printSlice(x []int){
   fmt.Printf("len = %d cap = %d slice = %v\n", len(x), cap(x),x)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

len = 9 cap = 9 slice = [0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len = 0 cap = 5 slice = []
len = 2 cap = 9  slice = [0 1]
len = 3 cap = 7 slice = [2 3 4]

Funções append () e copy ()

Pode-se aumentar a capacidade de uma fatia usando o append()função. Usandocopy()função, o conteúdo de uma fatia de origem é copiado para uma fatia de destino. Por exemplo -

package main

import "fmt"

func main() {
   var numbers []int
   printSlice(numbers)
   
   /* append allows nil slice */
   numbers = append(numbers, 0)
   printSlice(numbers)
   
   /* add one element to slice*/
   numbers = append(numbers, 1)
   printSlice(numbers)
   
   /* add more than one element at a time*/
   numbers = append(numbers, 2,3,4)
   printSlice(numbers)
   
   /* create a slice numbers1 with double the capacity of earlier slice*/
   numbers1 := make([]int, len(numbers), (cap(numbers))*2)
   
   /* copy content of numbers to numbers1 */
   copy(numbers1,numbers)
   printSlice(numbers1)   
}
func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

len = 0 cap = 0 slice = []
len = 1 cap = 2 slice = [0]
len = 2 cap = 2 slice = [0 1]
len = 5 cap = 8 slice = [0 1 2 3 4]
len = 5 cap = 16 slice = [0 1 2 3 4]

o range palavra-chave é usada em forloop para iterar sobre itens de uma matriz, fatia, canal ou mapa. Com matriz e fatias, ele retorna o índice do item como inteiro. Com mapas, ele retorna a chave do próximo par de valores-chave. O intervalo retorna um valor ou dois. Se apenas um valor for usado à esquerda de uma expressão de intervalo, será o primeiro valor na tabela a seguir.

Expressão de intervalo 1º valor 2º valor (opcional)
Matriz ou fatia a [n] E índice i int a [i] E
String s tipo de string índice i int runa int
mapa m mapa [K] V chave k K valor m [k] V
canal c chan E elemento e E Nenhum

Exemplo

O parágrafo a seguir mostra como usar o intervalo -

package main

import "fmt"

func main() {
   /* create a slice */
   numbers := []int{0,1,2,3,4,5,6,7,8} 
   
   /* print the numbers */
   for i:= range numbers {
      fmt.Println("Slice item",i,"is",numbers[i])
   }
   
   /* create a map*/
   countryCapitalMap := map[string] string {"France":"Paris","Italy":"Rome","Japan":"Tokyo"}
   
   /* print map using keys*/
   for country := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",countryCapitalMap[country])
   }
   
   /* print map using key-value*/
   for country,capital := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",capital)
   }
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Slice item 0 is 0
Slice item 1 is 1
Slice item 2 is 2
Slice item 3 is 3
Slice item 4 is 4
Slice item 5 is 5
Slice item 6 is 6
Slice item 7 is 7
Slice item 8 is 8
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo

Go fornece outro tipo de dados importante, denominado map, que mapeia chaves exclusivas para valores. Uma chave é um objeto que você usa para recuperar um valor em uma data posterior. Com uma chave e um valor, você pode armazenar o valor em um objeto Map. Depois que o valor é armazenado, você pode recuperá-lo usando sua chave.

Definindo um Mapa

Você deve usar make função para criar um mapa.

/* declare a variable, by default map will be nil*/
var map_variable map[key_data_type]value_data_type

/* define the map as nil map can not be assigned any value*/
map_variable = make(map[key_data_type]value_data_type)

Exemplo

O exemplo a seguir ilustra como criar e usar um mapa -

package main

import "fmt"

func main() {
   var countryCapitalMap map[string]string
   /* create a map*/
   countryCapitalMap = make(map[string]string)
   
   /* insert key-value pairs in the map*/
   countryCapitalMap["France"] = "Paris"
   countryCapitalMap["Italy"] = "Rome"
   countryCapitalMap["Japan"] = "Tokyo"
   countryCapitalMap["India"] = "New Delhi"
   
   /* print map using keys*/
   for country := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",countryCapitalMap[country])
   }
   
   /* test if entry is present in the map or not*/
   capital, ok := countryCapitalMap["United States"]
   
   /* if ok is true, entry is present otherwise entry is absent*/
   if(ok){
      fmt.Println("Capital of United States is", capital)  
   } else {
      fmt.Println("Capital of United States is not present") 
   }
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Capital of India is New Delhi
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of United States is not present

Função delete ()

A função delete () é usada para deletar uma entrada de um mapa. Requer o mapa e a chave correspondente que deve ser excluída. Por exemplo -

package main

import "fmt"

func main() {   
   /* create a map*/
   countryCapitalMap := map[string] string {"France":"Paris","Italy":"Rome","Japan":"Tokyo","India":"New Delhi"}
   
   fmt.Println("Original map")   
   
   /* print map */
   for country := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",countryCapitalMap[country])
   }
   
   /* delete an entry */
   delete(countryCapitalMap,"France");
   fmt.Println("Entry for France is deleted")  
   
   fmt.Println("Updated map")   
   
   /* print map */
   for country := range countryCapitalMap {
      fmt.Println("Capital of",country,"is",countryCapitalMap[country])
   }
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Original Map
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of India is New Delhi
Entry for France is deleted
Updated Map
Capital of India is New Delhi
Capital of Italy is Rome
Capital of Japan is Tokyo

Recursão é o processo de repetir itens de uma maneira semelhante. O mesmo conceito também se aplica a linguagens de programação. Se um programa permite chamar uma função dentro da mesma função, então é chamado de chamada de função recursiva. Dê uma olhada no seguinte exemplo -

func recursion() {
   recursion() /* function calls itself */
}
func main() {
   recursion()
}

A linguagem de programação Go oferece suporte à recursão. Ou seja, permite que uma função chame a si mesma. Mas, ao usar recursão, os programadores precisam ter cuidado para definir uma condição de saída da função, caso contrário, ela continuará a se tornar um loop infinito.

Exemplos de recursão em Go

As funções recursivas são muito úteis para resolver muitos problemas matemáticos, como cálculo fatorial de um número, geração de uma série de Fibonacci, etc.

Exemplo 1: Calculando fatorial usando recursão em Go

O exemplo a seguir calcula o fatorial de um determinado número usando uma função recursiva -

package main

import "fmt"

func factorial(i int)int {
   if(i <= 1) {
      return 1
   }
   return i * factorial(i - 1)
}
func main() { 
   var i int = 15
   fmt.Printf("Factorial of %d is %d", i, factorial(i))
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Factorial of 15 is 1307674368000

Exemplo 2: Série Fibonacci usando recursão em Go

O exemplo a seguir mostra como gerar uma série de Fibonacci de um determinado número usando uma função recursiva -

package main

import "fmt"

func fibonaci(i int) (ret int) {
   if i == 0 {
      return 0
   }
   if i == 1 {
      return 1
   }
   return fibonaci(i-1) + fibonaci(i-2)
}
func main() {
   var i int
   for i = 0; i < 10; i++ {
      fmt.Printf("%d ", fibonaci(i))
   }
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

0 1 1 2 3 5 8 13 21 34

A conversão de tipo é uma maneira de converter uma variável de um tipo de dados para outro. Por exemplo, se você deseja armazenar um valor longo em um número inteiro simples, você pode digitar cast long para int. Você pode converter valores de um tipo para outro usando ocast operator. Sua sintaxe é a seguinte -

type_name(expression)

Exemplo

Considere o exemplo a seguir, onde o operador de conversão faz com que a divisão de uma variável inteira por outra seja realizada como uma operação de número flutuante.

package main

import "fmt"

func main() {
   var sum int = 17
   var count int = 5
   var mean float32
   
   mean = float32(sum)/float32(count)
   fmt.Printf("Value of mean : %f\n",mean)
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Value of mean : 3.400000

A programação Go fornece outro tipo de dados chamado interfacesque representa um conjunto de assinaturas de método. O tipo de dados struct implementa essas interfaces para ter definições de método para a assinatura de método das interfaces.

Sintaxe

/* define an interface */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* define a struct */
type struct_name struct {
   /* variables */
}

/* implement interface methods*/
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* method implementation */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
   /* method implementation */
}

Exemplo

package main

import (
   "fmt" 
   "math" 
)

/* define an interface */
type Shape interface {
   area() float64
}

/* define a circle */
type Circle struct {
   x,y,radius float64
}

/* define a rectangle */
type Rectangle struct {
   width, height float64
}

/* define a method for circle (implementation of Shape.area())*/
func(circle Circle) area() float64 {
   return math.Pi * circle.radius * circle.radius
}

/* define a method for rectangle (implementation of Shape.area())*/
func(rect Rectangle) area() float64 {
   return rect.width * rect.height
}

/* define a method for shape */
func getArea(shape Shape) float64 {
   return shape.area()
}

func main() {
   circle := Circle{x:0,y:0,radius:5}
   rectangle := Rectangle {width:10, height:5}
   
   fmt.Printf("Circle area: %f\n",getArea(circle))
   fmt.Printf("Rectangle area: %f\n",getArea(rectangle))
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Circle area: 78.539816
Rectangle area: 50.000000

A programação Go fornece uma estrutura de tratamento de erros bastante simples com o tipo de interface de erro embutido da seguinte declaração -

type error interface {
   Error() string
}

As funções normalmente retornam erro como último valor de retorno. Usarerrors.New para construir uma mensagem de erro básica como a seguir -

func Sqrt(value float64)(float64, error) {
   if(value < 0){
      return 0, errors.New("Math: negative number passed to Sqrt")
   }
   return math.Sqrt(value), nil
}

Use o valor de retorno e a mensagem de erro.

result, err:= Sqrt(-1)

if err != nil {
   fmt.Println(err)
}

Exemplo

package main

import "errors"
import "fmt"
import "math"

func Sqrt(value float64)(float64, error) {
   if(value < 0){
      return 0, errors.New("Math: negative number passed to Sqrt")
   }
   return math.Sqrt(value), nil
}
func main() {
   result, err:= Sqrt(-1)

   if err != nil {
      fmt.Println(err)
   } else {
      fmt.Println(result)
   }
   
   result, err = Sqrt(9)

   if err != nil {
      fmt.Println(err)
   } else {
      fmt.Println(result)
   }
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Math: negative number passed to Sqrt
3