Declarações

Quando fazemos uma declaração, estamos atribuindo um identificador a uma entidade da aplicação, seja ela uma variável, uma constante, um tipo ou uma função. Veremos cada um desses termos com mais detalhes adiante, começando com variáveis.

Variáveis

Variáveis são espaços de memória que reservamos para guardar informações para posterior leitura através de um identificador.

Para declarar variáveis, utilizamos a palavra reservada var ou o operador curto de declaração := (a famosa marmota).

Sintaxe usando a palavra var:

1) var identificador tipo
2) var identificador tipo = valor
3) var identificador = valor

Sintaxe usando a marmota:

identificador := valor

Exemplo com tipos básicos mais utilizados:

package main

import (
	"fmt"
)

func main() {
	// Declarando variáveis
	var a string
	var b int
	var c float64
	var d bool

	fmt.Printf("Meu tipo é %T e meu valor é: '%v'\n", a, a)
	fmt.Printf("Meu tipo é %T e meu valor é: %v\n", b, b)	
	fmt.Printf("Meu tipo é %T e meu valor é: %v\n", c, c)
	fmt.Printf("Meu tipo é %T e meu valor é: %v\n", d, d)
}

O código acima cria variáveis dos tipos primitivos e imprime seu valor inicial. O %Té um especificador de formato que imprime o tipo da variável, %vformata o valor para o padrão genérico definido dentro da função print.

%vé uma forma mais fácil de indicar “imprima um valor na sua forma padrão".

Muita coisa aconteceu no exemplo anterior. Como estas variáveis receberam os valores que foram impressos na tela?

Go tem o conceito de valor zero. E o que isso significa? Significa que qualquer variável que é criada será, no mínimo, inicializada com seu valor inicial.

Go foca em integridade e esta inicialização é uma das formas de oferecê-la.

Outras linguagens de programação não implementam este conceito. Isso significa que, ao se criar uma variável sem a inicializar, não podemos garantir que a aplicação funcionará corretamente, pois seu valor é qualquer informação que já estava armazenada naquele espaço de memória.

Valores zero dos tipos primitivos de Go

int = 0

float = 0

string = ""

bool = false

Declarar a variável usando a palavra reservada var garante que a variável já será criada inicializada.

Mas palavra reservada var faz mais do que reservar espaço de memória para uma variável e inicializá-la com seu valor zero: ela também permite que o mesmo aconteça com uma lista de variáveis.

Exemplo de declaração de múltiplas variáveis:

package main

import (
	"fmt"
)

func main() {
	// Inicializando mais de uma váriavel ao mesmo tempo
	var somos, todos, gophers string

	fmt.Printf("Meu tipo é %T e meu valor é: '%v'\n", somos, somos)
	fmt.Printf("Meu tipo é %T e meu valor é: '%v'\n", todos, todos)
	fmt.Printf("Meu tipo é %T e meu valor é: '%v'\n", gophers, gophers)
}

Podemos também inicializá-las com valores diferentes dos seus valores zero.

Exemplo:

package main

import (
	"fmt"
)

func main() {
	// Inicializando mais de uma váriavel ao mesmo tempo
	// Nota: o tipo nao é mais necessário (tente removê-lo e rodar o código)

	var somos, todos, gophers string = "we are", "all", "gophers"

	fmt.Printf("Meu tipo é %T e meu valor é: '%v'\n", somos, somos)
	fmt.Printf("Meu tipo é %T e meu valor é: '%v'\n", todos, todos)
	fmt.Printf("Meu tipo é %T e meu valor é: '%v'\n", gophers, gophers)
}

Operador curto de declaração

Para atribuir valores diferentes dos iniciais usa-se o operador :=

Ele é chamado de short variable declaration (operador curto de declaração) ou productivity operator porque declara, inicializa e atribui valor à variável, sem necessidade de usar a palavra reservada var.

Sua sintaxe é a seguinte: identificador := valor , com identificador do lado esquerdo e valor do lado direito.

Quando o utilizamos, o tipo da variável é inferido, como podemos notar ao executar o exemplo abaixo.

Exemplo de declaração usando operador curto:

package main

import (
	"fmt"
)

func main() {
	// Declarando e inicializando variáveis
	// Note que não utilizamos mais a palavra reservada 'var'
	a := "wwg"
	b := 100
	c := 1.5
	d := true

	fmt.Printf("Meu tipo é %T e meu valor é: '%v'\n", a, a)
	fmt.Printf("Meu tipo é %T e meu valor é: %v\n", b, b)	
	fmt.Printf("Meu tipo é %T e meu valor é: %v\n", c, c)
	fmt.Printf("Meu tipo é %T e meu valor é: %v\n", d, d)
}

Constantes

Assim como as variáveis, constantes são espaços de memória que reservamos para guardar informações para posterior leitura através de um identificador, porém, seus valores não podem ser modificados após sua declaração.

Para declará-las, utilizamos a palavra reservada const. Falaremos sobre a sintaxe logo abaixo.

Por que usar uma constante em vez de uma variável?

É importante fazermos essa pergunta para entender em que situações devemos usar uma constante. Como não é possível modificar seu valor, devemos nos aproveitar dessa característica para declarar como constantes informações que não devem mudar de valor, como taxas, impostos, nomes imutáveis, valores que seriam "enum" em outras linguagens de programação.

Para declarar uma constante, podemos usar a seguinte sintaxe:

const nome tipo = valor

Caso o tipo seja omitido, será inferido de acordo com o valor.

No exemplo abaixo, vamos declarar a constante fatorEspecial:

package main

import (
	"fmt"
)

const fatorEspecial = 27

func main() {
	numero := 300
	total := numero * fatorEspecial
	fmt.Println(total)
}

O que acontece se eu tentar alterar o valor de uma constante?

Se rodarmos o código abaixo, que tenta alterar o valor da constante fatorEspecial, receberemos o erro de compilaçãocannot assign to fatorEspecial (declared const). Tente rodar aqui no Playground para ver o erro acontecendo.

package main

const fatorEspecial = 27

func main() {
	fatorEspecial = 30
}

Escopo

Vimos que as declarações associam um identificador a uma entidade da aplicação, e ele permite que posteriormente essa entidade seja acessada. Mas, podemos acessá-la de qualquer ponto da aplicação?

A resposta é: depende do seu escopo, que vamos ver nesse item, e da sua visibilidade, que vamos abordar logo abaixo.

Escopo é um termo bastante utilizado no desenvolvimento de software, e significa algo como "uma região da aplicação" ou, de forma mais abstrata, a abrangência de algo. Então, se falamos em escopo de uma variável, estamos falando da região onde aquela variável é conhecida.

Em Go, um grande indicador de escopo são as chaves { }. Elas indicam blocos sintáticos, pequenos "cercadinhos" de código, e uma entidade declarada dentro de um bloco sintático está disponível apenas dentro dele - desde sua declaração, até a chave (}) que o fecha.

Vamos exemplificar:

package main

import "fmt"

func main() {
	var nome = "Seu Nome"
	{
		fmt.Println(nome, ", a variável nome está disponível aqui!")
		numero := 230
		fmt.Println("A variável numero está disponível aqui, com valor", numero)
	}
	fmt.Println(numero, ", a variável numero não está disponível aqui!")
}

No exemplo acima, a variável numero está disponível apenas dentro do bloco onde foi declarada, mais especificamente da linha 9 (onde ocorreu sua declaração) até a chave de fechamento do bloco sintático em que ela está, na linha 11. Já a variável nome está disponível de sua declaração, na linha 6, até a chave de fechamento da função main(), na linha 13.

Tente rodar o código acima! Você receberá um erro similar a ./prog.go:12:14: undefined: numero.

Visibilidade

A primeira letra dos nomes das entidades em Go carrega um grande significado consigo: ela indica se aquela entidade poderá ser usada de fora ou apenas de dentro do pacote onde foi declarada.

Se a primeira letra for maiúscula, significa que a entidade será exportada, ou seja: ela poderá ser acessada por outro pacote. Se a primeira letra for minúscula, ela estará disponível apenas dentro do pacote onde foi declarada.

Last updated