Esse post faz parte de uma série onde pretendo compartilhar o básico essencial para desenvolver com GoLang.
No post anterior entendemos um pouco melhor de tipo de dados e ao fim eu mencionei alguns tipos de referência, nesse post vou dar um pouco mais detalhes, principalmente de Slices e Mapas, acredito que será bem importante para avançarmos para os próximos posts.
Estrutura de dados
Esse é um tópico bastante extenso, e um dos mais importantes dentro da ciência de computação, pode ser um pouco difícil para quem está iniciando, mas garanto que fica prazeroso de estudar e ver o quão genial são todas as possibilidades de estruturas.
Arrays
Um array é uma coleção de valores, nós vimos as variáveis, cada uma com seu tipo. O array vai te possibilitar ter vários valores de um mesmo tipo.
package main
import (
"fmt"
)
func main() {
// pode ser declarado com var seguido do [tamanho]tipo
var animes [3]string
animes[0] = "Gantz"
animes[1] = "Berserk"
animes[2] = "Attack on Titan"
fmt.Println(animes)
// também pode utilizar o operador ':=' e passar os valores entre as chaves
personagens := [3]string{"Kurono", "Guts", "Eren"}
fmt.Println(personagens)
// ou substituindo o tamanho por '...'
personagens = [...]string{"Kei Kishimoto", "Casca", "Mikasa"}
fmt.Println(personagens)
}
Uma coisa que fica evidente, arrays tem o tamanho definido em sua criação e eles são de tamanho fixo!
Slices
São muito similares aos Arrays, porém são dinâmicos e muito mais fáceis de trabalhar, a forma mais simples de criar um Slice é utilizando a função make
:
// make recebe o tipo []string e a capacidade inicial do slice
animes := make([]string, 3)
Perceba que a tipagem é muito similar a do array, e inicialmente o uso também é parecido. Bom, uma coisa importante de saber é que os Slices tem 3 propriedades:
- ponteiro para um array (novamente ponteiros, em breve falaremos disso!)
-
len
que é abreviação delength
, o tamanho atual do array. -
cap
abreviação decapacity
, quantos valores ele suporta armazenar.
package main
import (
"fmt"
)
func main() {
// cria um slice com tamanho 3
animes := make([]string, 3)
animes[0] = "Gantz"
animes[1] = "Berserk"
animes[2] = "Attack on Titan"
fmt.Println(animes)
fmt.Println(len(animes), cap(animes))
// a função append redimensiona a capacidade do slice
animes = append(animes, "Mob Psycho")
fmt.Println(animes)
fmt.Println(len(animes), cap(animes))
}
Tanto slices quanto arrays podem ser acessados pelo índice do valor:
personagens := [...]string{"Kei Kishimoto", "Casca", "Mikasa"}
fmt.Println(personagens[2])
E existe uma sintaxe muito interessante chamada slice-expression, que é uma maneira de extrair sub arrays/slices utilizando array[inicio:fim]
, por exemplo:
package main
import (
"fmt"
)
func main() {
personagens1 := [3]string{"Kurono", "Guts", "Eren"}
fmt.Println(personagens1)
fmt.Println(personagens1[0:2])
personagens2 := [3]string{"Kei Kishimoto", "Casca", "Mikasa"}
fmt.Println(personagens2)
fmt.Println(personagens2[2:3])
}
Quando usar Array e quando usar Slice ?
Na minha opinião o mais comum é utilizar Slices, por ter essa característica mais dinâmica. Isso simplifica muito o código, te evita ter que ficar recriando arrays e redimensionando.
É uma boa usar array quando você sabe exatamente o número de valores que precisa armazenar, ou se você quer fazer uma solução super otimizada, pelo fato de arrays não fazerem uso direto de um ponteiro 👀.
Vou deixar algumas referências, que explicam a diferença entre os dois bem melhor do que eu:
Map
Essa estrutura de dados vai fazer parte da sua vida pra sempre, brincadeiras a parte, ela resolve uma série de problemas e normalmente te ajuda a deixar o seu código mais otimizado.
As principais características de um mapa é que ele é uma coleção de pares, ou melhor, de chaves e valores. E ele não é ordenado, pois trabalha com o conceito de hash, ou espalhamento.
Em outras linguagens você vai encontrar Map com outros nomes, por exemplo: dict
, hash
, Hashtable
e HashMap
package main
import (
"fmt"
)
func main() {
// são iniciados com make, é opcional informar a capacidade inicial
// e assim é definido map[tipo da chave]tipo do valor
dicionario := make(map[string]string)
dicionario["hi"] = "oi"
dicionario["bye"] = "tchau"
dicionario["hey"] = "opa"
fmt.Println(dicionario)
// também podem ser iniciados com valores literais
personagemAnime := map[string]string{
"Eren": "Attack on Titan",
"Guts": "Berserk",
"Kurono": "Gantz",
}
fmt.Println(personagemAnime)
}
Modificando Map
Quando você estiver resolvendo um problema com um mapa, seja um de-para, um agrupamento de dados, sumarizando totais, etc. Você vai precisar de forma incremental modificar o mapa, e para isso você precisa conhecer algumas poucas operações:
// recuperar um valor associado a uma chave
anime := personagemAnime["Eren"]
fmt.Println(anime)
// recuperar um valor associado a uma chave, e conferir se ele existe
anime, ok := personagemAnime["Naruto"]
// a variavel ok vai ser um bool sinalizando se a chave existe ou não.
fmt.Println(anime, ok)
// deleta a chave e o valor associado do mapa
delete(personagemAnime, "Kurono")
// para atualizar ou inserir
personagemAnime["Kurono"] = "Gantz"
Desde a criação até essas operações a forma de manusear um mapa é muito parecida com slice/array. Esses pequenos detalhes fazem do Go uma linguagem tão simples.
E agora?
Voltaremos a ver Slices e Mapas quando falarmos de controle de fluxo e iterações!
Nesse momento eu vou limitar nas estruturas simples do Go, até nesse sentido a linguagem foi bastante simplificada tendo um número bem reduzido de estrutura de dados se comparado a outras linguagens. Por um lado isso é bom, pois facilita muito para quem é iniciante, o estudo é mais curto. Mas por favor, não pare nas estruturas básicas do Go 🙏.
Vou deixar algumas referências que podem ajudar a seguir com os estudos:
Junmin Lee - Tem uma série de estrutura de dados implementadas em Go
Programação Dinâmica - Conta com série de estrutura de dados em português.
Inclusive esse canal tem muito material bom com uma didática excelente, vale muito a pena se inscrever!
Resumo
- arrays são coleções de um mesmo tipo de tamanho fixo.
- slices são coleções de um mesmo tipo com tamanho dinâmico.
- mapas são coleções não ordenadas de chaves e valores.
- slices e mapas são inicializados com a função
make()