Tipos Compostos em Go
Olá Leitor, seja bem vindo a mais uma lição da jornada GoLang 😄
Em lições anteriores, você aprendeu um pouco sobre a utilização dos tipos básicos em GoLang, ainda se lembra deles?
Não? Então deixa eu refrescar sua memória:
string
int
float
complex
bool
Se ainda não sabe como utilizá-los, recomendo que dê uns passos atrás, e volte na lição que fala sobre eles 🤭
Hoje, nós iremos aprender sobre os tipos compostos, ou também conhecidos como composite types
, que representam um passo a mais sobre os tipos básicos.
O que são tipos compostos?
Em GoLang, nós temos os tipos array
, slice
e map
, que são conhecidos como tipos compostos, eles são chamados dessa maneira pois por de baixo dos panos, eles são construídos a partir de outros tipos, como os próprios tipos básicos (int
, string
, float64
, etc.).
Mas para que você possa entender o que de fato são os tipos compostos, primeiro você aprender o que são matrizes e vetores em uma linguagem de programação.
Basicamente, uma matriz (arrays multidimensionais) nada mais são do que estruturas que são capazes de armazenar e manipular coleções de valores, como listas de produtos, registros de clientes, listas de nomes, listas de números e etc.
Essas estruturas de dados são fundamentais, pois são a partir delas que conseguimos e armazenar informações na memória, de modo a facilitar o acesso e a manipulação de informações e dados.
Pense em uma matriz como se fosse uma caixa, onde dentro dela existe diversas subdivisões com seus respectivos nomes ou índices (números que vão de 0 a N).

Caso preferir, você também pode pensar numa matriz como uma planilha do excel, onde cada linha e coluna é usada para o armazenamento de dados.
Isso dá a possibilidade do desenvolvedor ter dentro de uma mesma "caixa" (ou planilha) diversos tipos de dados diferentes.
O que é uma matriz?
No mundo da programação e tecnologia, uma matriz é como uma tabela organizada em linhas (horizontais) e colunas (verticais)
Onde cada posição dentro dessa tabela é chamada de célula na qual podemos identificar cada uma usando dois números:
- Primeiro número: indica a linha (de cima para baixo).
- Segundo número: indica a coluna (da esquerda para a direita).
As posições na matriz são identificadas por dois números entre colchetes [linha]
[coluna]
. Por exemplo:
- A célula no canto superior esquerdo é
[0][0]
. - A célula no canto inferior direito é
[2][2]
.
Assim como também funciona nas planilhas do excel, onde a primeira célula é sempre a A1, a segunda é A2, e assim por diante...
Para que você possa entender melhor, vamos dar uma olhada nessa ilustração abaixo:

Imagine que essa matriz acima é como uma prateleira de frutas, onde cada caixinha é responsável por armazenar uma fruta por vez.
E para encontrar uma fruta específica, você precisa dizer o número da linha e a coluna, assim como você o faria caso estivesse usando um mapa 🗺️
Por exemplo, para você pegar a banana basta ir até a posição [1][5]
, ou seja, primeira linha na quinta coluna.
Além das matrizes multidimensionais, existem matrizes mais simples, chamadas de matrizes unidimensionais, que em GoLang são conhecidos como arrays
(ou vetores).
Eles são mais simples porque têm apenas uma direção (ou seja, uma única linha de elementos).
Um array
é como uma fila ou uma linha de caixas. Cada caixa guarda um valor, e você pode acessar qualquer um deles usando um número chamado índice, vejamos um exemplo:

🧮 Como funciona o índice?
- O primeiro elemento está na posição
0
. - O segundo está na posição
1
. - E assim por diante.
Nesse caso, para acessar o valor 30
por exemplo, basta informar a posição [2]
🙂
Observação: a contagem de um array
e um slice
no GoLang sempre começa no índice 0, e não no índice 1.
Agora que você já sabe o que é uma matriz, podemos finalmente colocar a mão na massa e aprender um pouco mais sobre como criar arrays
, slices
e maps
no GoLang!
Preparado?
Criando seu projeto de testes
Dentro da pasta JornadaGoLang, nós iremos criar uma nova pasta chamada de 10-tipos-compostos-em-go
, onde dentro dela, vamos criar o nosso arquivo main.go
:
package main
func main(){
}
Feito isso, vamos aprender um pouco mais sobre tipos compostos em GoLang 😁
Trabalhando com Arrays em Go
Começando pelo mais tradicional, dentro do GoLang (assim como na maioria das outras linguagens de programação) nós temos os arrays
.
Os arrays
são estruturas homogêneas, isto é, devem sempre armazenar o tipo declarado em toda a sua estrutura (se você declarar um array de strings, ele só poderá armazenar string, e assim também funciona com os outros tipos básicos), além disso, a sua própria estrutura precisa ser fixa.
Isso significa dizer que se você definir um array
com 10 posições, ele deve permanecer com 10 posições e isso nunca poderá ser alterado.
Se você definir um array do tipo int, ele deverá apenas armazenar tipos inteiros, e isso nunca poderá ser alterado. (A mesma coisa vale para os outros tipos)
A sintaxe de um array
em GoLang é a seguinte:
var nome_do_array [tamanho]tipo
Primeiro você declara a variável contendo o nome da sua lista (nome_do_array
), seguido do tamanho informado dentro dos colchetes ([tamanho]
), e seu tipo (tipo básico, podendo ser string, int, float e etc) no final.
Vejamos um exemplo prático:
package main
func main(){
var meuArray [10]string
}
No exemplo acima, criamos uma variável chamada meuArray
, que deverá armazenar até 10 strings.
Se mostrarmos os valores existentes dentro desse array
que acabamos de criar usando o Println()
:
package main
import "fmt"
func main(){
var meuArray [10]string
fmt.Println(meuArray)
}
Teremos o seguinte resultado:
[ ]
Ué, mas não retornou nada? 😅
É obvio rs
Pois tudo o que fizemos acima foi apenas declarar nosso array, nós não definimos nenhum valor que será amazenado, somente seu tamanho e o seu tipo.
Caso tivéssemos criado um array de inteiros:
package main
import "fmt"
func main() {
var meuArrayDeInteiros [7]int
fmt.Println(meuArrayDeInteiros)
}
Veríamos esse resultado no terminal:
[0 0 0 0 0 0 0]
Ué? Porque aqui ele retornou diversos ZEROS, e anteriormente ele não retornou nada?
No caso do meuArray
, foi retornado diversos espaços em branco, representando nossas strings
vazias. Já no caso do meuArrayDeInteiros
, ele sempre vai armazenar o menor valor do tipo int
, e qual é o menor valor do tipo int
?
Isso mesmo, o número 0
🥳
Inserindo valores dentro de arrays em Go
Para inicializarmos o nosso array de strings, podemos fazer isso de algumas formas diferentes:
🟢 Atribuição manual: nela pode atribuir valores a posições específicas usando os índices:
package main
import "fmt"
func main() {
var meuArray [10]string
// Atribuindo valores por índice
meuArray[0] = "Maçã"
meuArray[1] = "Banana"
meuArray[9] = "Uva"
fmt.Println(meuArray) // Saída: [Maçã Banana Uva]
}
Note que como os índices 2
, 3
, 4
, 5
, 6
, 7
e 8
não foram inicializados, eles permanecem em branco.
🔵 Atribuição durante a declaração: Se já souber os valores, você pode preencher o array imediatamente:
package main
import "fmt"
func main() {
var meuArray = [10]string{"Maçã", "Banana", "Uva", "Pera"}
fmt.Println(meuArray)//[Maçã Banana Uva Pera ]
}
Note que durante a declaração, usamos as chaves para definir os elementos, além disso a string
"Maçã" sempre começa no índice 0
, e assim por diante.
🟡 Tipo de inferência: Com o comando :=
, você pode deixar o Go deduzir o tipo do array:
package main
import "fmt"
func main() {
meuArray := [10]string{"Maçã", "Banana", "Uva"}
fmt.Println(meuArray)//[Maçã Banana Uva ]
}
🔴 Inicializar com tamanho implícito: Também é possível inicializar um array fazendo com que o Go conte os elementos de maneira automática, para isso basta usar o [...]
:
package main
import "fmt"
func main() {
meuArray := [...]string{"Maçã", "Banana", "Uva"}
fmt.Println(meuArray) // Saída: [Maçã Banana Uva]
}
🟠 Inicializando informando índices específicos: Você pode definir valores em índices específicos:
package main
import "fmt"
func main() {
meuArray := [10]string{0: "Maçã", 3: "Banana", 9: "Uva"}
fmt.Println(meuArray) // Saída: [Maçã Banana Uva]
}
Note que durante a declaração, eu informei os índices de onde cada string
deverá se posicionar.
🟣 Preencher com valores repetidos: Se quiser repetir valores ou seguir um padrão, um for ajuda:
package main
import "fmt"
func main() {
var meuArray [10]string
for i := 0; i < len(meuArray); i++ {
meuArray[i] = "Fruta"
}
fmt.Println(meuArray) // Saída: [Fruta Fruta Fruta ...]
}
Note que usamos a função len()
, que por sua vez, tem a capacidade de retornar o valor numérico contendo a quantidade de elementos existentes em um array
.
package main
import "fmt"
func main() {
meuArray := [5]int{10, 20, 30, 40, 50}
fmt.Println("Tamanho do array:", len(meuArray)) // Saída: 5
}
Observação: A função len()
em GoLang é usada para retornar o comprimento (tamanho) de estruturas como arrays
, slices
, strings
e maps
.
Varrendo arrays usando o for
Agora que você já sabe como criar arrays
, que tal aprender a percorrer toda a sua estrutura de forma automática?
Em lições anteriores, você aprendeu a utilizar a estrutura de controle chamada for
:
package main
import "fmt"
func main() {
for i := 0; i < 9; i++ {
fmt.Println("Contador:", i)
}
//O comando acima fará a contagem de 0 até 9.
}
E será por meio dela que você aprenderá a percorrer um array
😋
Supondo que temos um array
com 15 números inteiros:
package main
import "fmt"
func main() {
// Declarando um array com 15 números inteiros
numeros := [15]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
}
E que desejamos percorrer este array
mostrando cada um dos valores ali contidos dentro de um terminal, podemos usar o for
da seguinte forma:
package main
import "fmt"
func main() {
// Declarando um array com 15 números inteiros
numeros := [15]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
// Percorrendo o array com um for tradicional
for i := 0; i < len(numeros); i++ {
fmt.Printf("Índice: %d, Valor: %d\n", i, numeros[i])
}
}
Uma outra forma mais concisa de se percorrer um array
usando o for
, é em conjunto com o range
:
package main
import "fmt"
func main() {
numeros := [15]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
// Percorrendo o array com for range
for indice, valor := range numeros {
fmt.Printf("Índice: %d, Valor: %d\n", indice, valor)
}
}
É importante ressaltar que o comando range
em GoLang é usado para iterar (percorrer) diferentes tipos de estruturas de dados, tais como:
- Arrays (matrizes unidimensionais)
- Slices (listas dinâmicas)
- Maps (dicionários ou tabelas de chave-valor)
- Strings (sequências de caracteres)
- Canais (channels) (para comunicação concorrente)
Vejamos outro exemplo:
package main
import "fmt"
func main() {
frutas := []string{"maçã", "banana", "uva"}
for i, fruta := range frutas {
fmt.Printf("Índice: %d, Fruta: %s\n", i, fruta)
}
}
Observação: o exemplo acima não declarou um array
sem limites, mas sim uma slice
, tipo composto na qual você irá aprender no próximo tópico 😄
É possível remover índices de um array?
Não é possível remover um índice diretamente de um array
, pois o tamanho do array
não pode ser alterado após a sua declaração.
Para "remover" um elemento de um array
, você teria que criar um novo array
com um tamanho menor, sem o elemento que você deseja remover, por exemplo:
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
indexToRemove := 2 // Queremos remover o índice 2 (o valor 3)
// Criando um novo array com 4 elementos
var newArr [4]int
copy(newArr[:], append(arr[:indexToRemove], arr[indexToRemove+1:]...))
fmt.Println("Array original:", arr)
fmt.Println("Novo array:", newArr)
}
O append()
é utilizado para juntar essas duas slices
em uma nova slice
, efetivamente removendo o elemento no índice desejado.
Trabalhando com Slice
Uma slice
é uma sequência de elementos de um tipo específico, mas ao contrário de um array
, seu tamanho pode variar ao longo do tempo. Ela é, na verdade, uma abstração sobre arrays
, oferecendo mais flexibilidade.
Ao contrário de arrays, que têm um tamanho fixo, slices são dinâmicas e podem ser redimensionadas durante a execução do programa.
A sintaxe de uma slice
é a seguinte:
var nome_do_slice []tipo
Note que definimos um colchete vazio, indicando que seu tamanho é ilimitado.
Vejamos como declarar uma slice
:
package main
import "fmt"
func main() {
frutasUm := []string{"maçã", "banana", "uva"}
var frutasDois []string
}
No comando acima, declaramos dois slices
, o primeiro com valores pré-definidos, e o seguindo com valores vazios. No caso dos dois, é possível adicionar mais elementos dentro de cada um deles.
Caso desejar, você pode inicializar uma slice
vazia com capacidade de 10 elementos usando a função make
:
frutas := make([]string, 0, 10)
A função make([]type, length, capacity)
cria uma slice
com o tipo especificado, com o comprimento e capacidade informados.
Operações mais comuns com slices
Assim como acontece nos arrays
, nós podemos acessar elementos de uma slice
utilizando um índice da seguinte forma:
fmt.Println(frutasUm[0]) // Imprime o primeiro elemento, "maçã"
Caso queira adicionar elementos dentro de uma slice
, use a função append()
:
frutas = append(frutas, "laranja") // Adiciona "laranja" à slice
Nota: A função append()
pode criar uma nova slice
se a capacidade da slice
original for insuficiente para armazenar o novo elemento.
Além disso, você pode criar uma nova slice
a partir de uma slice
existente, especificando um intervalo de índices:
frutasSubset := frutas[1:3] // Cria uma slice com os elementos de índice 1 e 2
Vejamos agora um exemplo de uma slice
sendo percorrida por um for
, onde ignoramos seu índice por meio da anotação _
:
package main
import "fmt"
func main() {
frutas := []string{"maçã", "banana", "uva"}
for _, fruta := range frutas {
fmt.Printf("Fruta: %s\n", i, fruta)
}
}
Vejamos um outro exemplo, onde a função append()
é usada para redimensionar automaticamente a slice
se a capacidade for excedida:
nums := []int{1, 2, 3}
nums = append(nums, 4) // nums agora é [1, 2, 3, 4]
Medindo o comprimento e capacidades de um array e slice
Como dito anteriormente, nós temos dois grandes aliados que podem nos ajudar a medir a capacidade de um array
e uma slice
, são eles:
len()
: Retorna o número de elementos de uma sequência (array, slice ou string)
cap()
: Retorna a capacidade total (número máximo de elementos) que a sequência pode armazenar antes de uma nova alocação de memória ser necessária.
Vejamos um exemplo de seus usos:
package main
import "fmt"
func main() {
s := []int{1, 2, 3}
fmt.Println(len(s), cap(s)) // Inicialmente len = 3, cap = 3
s = append(s, 4) // Adiciona um elemento, a capacidade pode ser duplicada
fmt.Println(len(s), cap(s)) // Agora len = 4, cap = 6 (ou algo maior, dependendo da implementação)
}
Criando uma slice de uma slice
Em alguns momentos, você vai se deparar com uma sintaxe similar a esta [:a3]
, mas não se desespere, ela é mais fácil de se entender do que você imagina.
Em GoLang, você pode criar um fatiamento (slicing) de uma slice
. O fatiamento permite extrair uma parte (ou subsequência) de uma slice
, usando um intervalo de índices.
slice[inicio:fim]
inicio
: Índice onde o fatiamento começa (inclusivo). Se omitido, assume-se 0 (começa do início).
fim
: Índice onde o fatiamento termina (exclusivo). Se omitido, a slice
vai até o final.
Vejamos o exemplo a seguir:
package main
import "fmt"
func main() {
frutas := []string{"maçã", "banana", "uva", "laranja", "morango"}
// Fatiamento até o índice 3 (não inclui o elemento no índice 3)
parte := frutas[:3]
fmt.Println(parte) // Imprime: [maçã banana uva]
}
Neste exemplo, [:3]
significa que estamos pegando os elementos nos índices 0
, 1
e 2
da slice
frutas, ou seja, as três primeiras frutas
.
package main
import "fmt"
func main() {
frutas := []string{"maçã", "banana", "uva", "laranja", "morango"}
// Fatiamento da posição 2 até o final
parte := frutas[2:]
fmt.Println(parte) // Imprime: [uva laranja morango]
}
No exemplo acima, [2:]
significa "começar do índice 2 (inclusive) até o final da slice".
package main
import "fmt"
func main() {
frutas := []string{"maçã", "banana", "uva", "laranja", "morango"}
// Fatiamento do índice 1 até o índice 4 (não inclui o 4)
parte := frutas[1:4]
fmt.Println(parte) // Imprime: [banana uva laranja]
}
Aqui, [1:4]
pega os elementos nos índices 1
, 2
e 3
da slice
frutas, ou seja, "banana", "uva" e "laranja".
Você também pode criar fatiamentos para criar subsequências específicas:
package main
import "fmt"
func main() {
frutas := []string{"maçã", "banana", "uva", "laranja", "morango"}
// Fatiamento das duas primeiras frutas
parte1 := frutas[:2]
fmt.Println(parte1) // Imprime: [maçã banana]
// Fatiamento das duas últimas frutas
parte2 := frutas[3:]
fmt.Println(parte2) // Imprime: [laranja morango]
// Combinando as duas partes
resultado := append(parte1, parte2...)
fmt.Println(resultado) // Imprime: [maçã banana laranja morango]
}
[:a3]
: Cria uma novaslice
desde o início até o índicea3-1
.[a1:a2]
: Cria uma novaslice
desde o índicea1
até o índicea2-1
.[a1:]
: Cria uma novaslice
desde o índicea1
até o final.[:a2]
: Cria uma novaslice
do início até o índicea2-1
.
Criando slices com make
No GoLang, você consegue criar um slice
usando a função make
da seguinte forma:
make([]tipo, comprimento, capacidade)
A função make()
é usada para criar slices
, maps
e channels
, mas aqui vamos falar especificamente sobre como ela funciona para uma slice
.
tipo
: O tipo dos elementos da slice
(como int, string, float64, etc.).
comprimento
: O número de elementos iniciais na slice. Este valor também será o valor retornado por len()
da slice
.
capacidade (opcional)
: A capacidade máxima da slice
antes de uma realocação de memória. Se não for fornecido, a capacidade será igual ao comprimento.
Vejamos um exemplo:
package main
import "fmt"
func main() {
// Criando uma slice de inteiros com comprimento 3 e capacidade 5
s := make([]int, 3, 5)
fmt.Println(s) // Imprime: [0 0 0]
fmt.Println(len(s)) // Imprime: 3 (comprimento)
fmt.Println(cap(s)) // Imprime: 5 (capacidade)
}
No exemplo acima, criamos uma slice
que começa com 3
elementos, e todos os elementos são inicializados com o valor zero para o tipo (0
para int
).
A capacidade total da slice
é 5
, o que significa que ela pode crescer até 5
elementos antes de precisar de uma realocação de memória.
Vejamos um outro exemplo, na qual estamos criando uma slice
modificando seus elementos:
package main
import "fmt"
func main() {
// Criando uma slice de strings com comprimento 2 e capacidade 3
s := make([]string, 2, 3)
// Modificando os elementos da slice
s[0] = "maçã"
s[1] = "banana"
fmt.Println(s) // Imprime: [maçã banana]
fmt.Println(len(s)) // Imprime: 2
fmt.Println(cap(s)) // Imprime: 3
}
Caso desejar, você pode criar uma slice
com apenas o comprimento sem capacidade especificada:
package main
import "fmt"
func main() {
// Criando uma slice de inteiros com comprimento e capacidade 3
s := make([]int, 3)
fmt.Println(s) // Imprime: [0 0 0]
fmt.Println(len(s)) // Imprime: 3
fmt.Println(cap(s)) // Imprime: 3
}
Após a criação de uma slice
com make()
, você pode expandi-la além da capacidade inicial usando a função append()
.
Quando isso acontece, o Go automaticamente realoca a memória conforme necessário:
package main
import "fmt"
func main() {
// Criando uma slice com comprimento 2 e capacidade 3
s := make([]int, 2, 3)
// Adicionando elementos à slice
s = append(s, 4, 5) // Agora a slice tem 4 elementos
fmt.Println(s) // Imprime: [0 0 4 5]
fmt.Println(len(s)) // Imprime: 4 (comprimento atualizado)
fmt.Println(cap(s)) // Imprime: 6 (capacidade pode ter sido dobrada)
}
Usando a função copy
A função copy()
em Go é usada para copiar elementos de uma slice
para outra. Ela é útil quando você deseja duplicar uma slice
ou copiar parte de uma slice
para outra.
Sua sintaxe é a seguinte:
copy(destino, origem)
destino
: A slice
que irá receber os elementos (a slice de destino).
origem
: A slice
da qual os elementos serão copiados (a slice de origem).
Retorno: Um int
indicando o número de elementos copiados.
Vejamos um exemplo do seu uso:
package main
import "fmt"
func main() {
origem := []int{1, 2, 3, 4, 5}
destino := make([]int, len(origem))
n := copy(destino, origem)
fmt.Println("Origem:", origem) // [1 2 3 4 5]
fmt.Println("Destino:", destino) // [1 2 3 4 5]
fmt.Println("Elementos copiados:", n) // 5
}
Incrível, não acha? 😄
É possível ter dois tipos básicos em um array ou slice no Go?
Esse é um tipo de pergunta que sempre vem à tona quando estamos trabalhando com array
ou slices
na linguagem GoLang.
E apesar dos arrays
e slices
serem estruturas homogêneas, ou seja, todos os elementos devem ser do mesmo tipo. Você pode utilizar interfaces
para armazenar diferentes tipos em um mesmo array
ou slice
.
Observação: nós ainda não entramos no conceito de interfaces
, portanto, não se sinta mal caso não souber o que é isso ainda 😆
No GoLang, você pode ter mais de um tipo básico por meio do uso de interface
, e isso pode ser feito da seguinte forma:
package main
import "fmt"
func main() {
// Slice que armazena diferentes tipos de dados
mixedSlice := []interface{}{42, "texto", 3.14, true}
for _, v := range mixedSlice {
fmt.Printf("Valor: %v, Tipo: %T\n", v, v)
}
}
Exemplo de saída:
Valor: 42, Tipo: int
Valor: texto, Tipo: string
Valor: 3.14, Tipo: float64
Valor: true, Tipo: bool
Já com a chegada da versão 1.18+, o GoLang ganhou um novo tipo específico chamado de any
, que aceita qualquer tipo básico:
package main
import "fmt"
func main() {
var mixed []any = []any{123, "olá", 4.56}
for _, item := range mixed {
fmt.Printf("Valor: %v, Tipo: %T\n", item, item)
}
}
Trabalhando com Map em Go
Não é só de índices numéricos que vivem as listas em GoLang, sabia?
Mas como também podemos criar listas de chave e valor, onde neste caso, conseguimos fazer de um índice númerico uma string ou qualquer outro tipo básico.
No Go, maps
(ou dicionários em outras linguagens) são estruturas que armazenam pares de chave-valor. No entanto:
✅ As chaves de um map não se limitam a números: podem ser de qualquer tipo comparável (ex.: string, int, float, complex, bool etc.).
❌ Não podemos usar tipos não comparáveis: como chave, por exemplo, um slice
, map
ou uma função.
A sintaxe de um map
é a seguinte:
map[TipoDaChave]TipoDoValor
Vamos ver um exemplo básico de sua utilização:
package main
import "fmt"
func main() {
// Criando um map com chave string e valor int
idades := map[string]int{
"Alice": 30,
"Bob": 25,
"Eve": 22,
}
fmt.Println(idades) // Saída: map[Alice:30 Bob:25 Eve:22]
}
No exemplo acima, inicializamos um map
, cujo as chaves (índices) serão strings
, e seus respectivos valores serão inteiros (int
).
Para criar um map
vazio afim de preenchê-lo depois, a função make()
pode te ajudar com isso, observe:
contagem := make(map[string]int) // Cria um map vazio
contagem["Maçã"] = 5
contagem["Banana"] = 3
fmt.Println(contagem) // Saída: map[Maçã:5 Banana:3]
Caso, desejar, você pode adicionar e atualizar valores em um map
da seguinte forma:
pontos := make(map[string]int)
pontos["João"] = 50 // Adiciona um novo par
pontos["Ana"] = 75 // Adiciona outro par
pontos["João"] = 100 // Atualiza um valor existente
fmt.Println(pontos) // Saída: map[Ana:75 João:100]
Além disso, é possível acessar os valores de um map
da seguinte forma, bastando apenas informar seu índice:
notas := map[string]float64{
"Matemática": 9.5,
"História": 8.0,
}
fmt.Println(notas["Matemática"]) // Saída: 9.5
Para remover itens de um map
, você pode utilizar a função delete()
da seguinte forma:
nomes := map[string]string{
"123": "Carlos",
"456": "Ana",
}
delete(nomes, "123") // Remove o item com a chave "123"
fmt.Println(nomes) // Saída: map[456:Ana]
Para verificar se uma determinada chave (índice) em um map
existe, faça isso da seguinte forma:
idades := map[string]int{"João": 30}
idade, existe := idades["Ana"]
if existe {
fmt.Println("Idade encontrada:", idade)
} else {
fmt.Println("Chave não encontrada")
}
Observação: Se a chave não existir, o valor retornado será o zero value
do tipo básico escolhido (ex.: 0 para int, "" para string).
Para percorrer um map
, você também pode utilizar a mesma estratégia de for
em conjunto com range
, como estamos acostumados, observe:
frutas := map[string]int{
"Maçã": 5,
"Banana": 3,
"Laranja": 2,
}
for chave, valor := range frutas {
fmt.Printf("%s: %d\n", chave, valor)
}
Para limpar um map, basta usar o make()
da seguinte forma:
meuMapa = make(map[string]int) // Novo map vazio
É importante ressaltar que maps
são passados por referência, ou seja, modificações em uma cópia afetam o original, vamos ver um exemplo:
original := map[string]int{"A": 1}
copia := original
copia["A"] = 42
fmt.Println(original) // Saída: map[A:42]
Para realizar uma cópia totalmente independente, faça isso da seguinte forma:
novo := make(map[string]int)
for k, v := range original {
novo[k] = v
}
Aninhando Maps
Você sabia que é possível criar uma estrutura de chave e valor dentro de outra, e assim sucessivamente?
Não, pois saiba que com o map
isso é totalmente possível, observe como isso pode ser feito:
notas := map[string]map[string]float64{
"João": {
"Matemática": 9.5,
"História": 8.0,
},
"Ana": {
"Matemática": 10.0,
"História": 9.0,
},
}
fmt.Println(notas["João"]["Matemática"]) // Saída: 9.5
No Go, não há um limite explícito de profundidade para mapas aninhados. Em teoria, você pode aninhar quantos map
quiser, desde que a memória do seu sistema suporte.
package main
import "fmt"
func main() {
estrutura := map[string]map[string]map[string]int{
"primeiro": {
"segundo": {
"terceiro": 42,
},
},
}
fmt.Println(estrutura["primeiro"]["segundo"]["terceiro"]) // Saída: 42
}
Vejamos outro exemplo:
estrutura := make(map[string]map[string]map[string]int)
estrutura["nivel1"] = make(map[string]map[string]int)
estrutura["nivel1"]["nivel2"] = make(map[string]int)
estrutura["nivel1"]["nivel2"]["nivel3"] = 99
fmt.Println(estrutura["nivel1"]["nivel2"]["nivel3"]) // Saída: 99
Tipos permitidos em chaves de map
É importante que você conheça os tipos permitidos e que podem ser usados como chaves (índices) em um map
😁
✅ int
, string
, float64
, bool
, struct
(se comparável), podem ser utilizados como chave.
❌ Entretanto, não é possível usar slice
, map
ou função como chave.
Repositório da lição
Todos os arquivos relacionados com esta lição, podem ser encontrados nos seguintes repositórios abaixo:
Conclusão
Nesta lição, você aprendeu a usar os tipos compostos slice
, map
e array
.
Na próxima lição, vamos entrar em conceitos um pouco mais avançados como structs
, heranças
e interfaces
.
Até logo 🤩