Slices
O que acontece por baixo dos panos e como melhorar um pouco a performance

Os slices representam uma forma mais poderosa e dinâmica de trabalhar com coleções ou sequências de dados em go, eles são um tipo de dado composto por outros tipos, nesse caso um array usado como base, um inteiro para indicar o tamanho do slice e um outro inteiro para indicar a capacidade do slice, que também pode ser entendido como o tamanho do array base.
Com os slices é possível, por exemplo, ter uma estrutura de dados de tamanho dinâmico, aumentando conforme o necessário, este tipo de operação obviamente tem um custo, devemos entender que existe um tradeoff entre ter uma estrutura que suporta coleções de forma dinâmica e a performance do nosso código, pois todo tipo de dado que suporte coleções de tamanho dinâmico tem um mecanismo que por trás faz uso de um array de tamanho fixo, e toda operação de inclusão de um novo item precisa alocar um novo array maior que o primeiro e copiar todos os itens para o novo array, e é isso que acontece dentro de um slice quando fazemos um append() que é a forma de incluirmos um novo item.
Ex: playground
package main
import (
"fmt"
)
func main() {
a1 := []int{1,2,3,4}
fmt.Printf("tamanho do slice %d, tamanho do array %d\n", len(a1), cap(a1))
a1 = append(a1, 5)
fmt.Printf("tamanho do slice %d, tamanho do array %d\n", len(a1), cap(a1))
}
Conforme dito este tipo de operação tem um impacto na performance, que pode ser tornar considerável em escalas maiores, sendo assim seria interessante que pudéssemos ter um controle maior sobre o tamanho do array base utilizado na composição do slice, ou capacidade do slice, pois como vimos no exemplo, quando criamos um slice através de um composite literal é criado um array com o mesmo tamanho do slice nos obrigando a executar uma operação de realocação dos itens logo na primeira expansão. Controlando a capacidade do slice podemos controlar a partir de quando será necessária a criação de um novo array e a cópia dos elementos para o mesmo, este controle pode ser obtido usando a função make, que é usada em go para inicializar tipos que não são primitivos como slice , chanels e maps, que são compostos de outros tipos.
Ex: playground
package main
import (
"fmt"
)
func main() {
a1 := make([]int, 0, 6)
for i := 0; i < 4; i++ {
a1 = append(a1, i)
fmt.Printf("tamanho do slice %d, tamanho do array %d\n", len(a1), cap(a1))
}
}
Conforme vimos no exemplo por mais que chamemos o append, desde que dentro do tamanho esperado, não houve necessidade de criar um novo array base e copiar os itens, desta forma temos mais controle sobre quando e se a realocação deve acontecer.
Alocar um slice desta forma é uma ferramenta que nos permite ter maior controle sobre o uso de recursos do nosso programa sem tornar isso algo demasiadamente complexo, porém com grandes poderes vem algumas responsabilidades devemos ter atenção e pensar de forma ampla para extrair a melhor performance do nosso programa.






![[Repost] Código limpo precisa também ser simples](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1671555713609%2Fv8SIJtHTn.jpeg&w=3840&q=75)