---
title: "Go 1.21: Novidades e Recursos"
url: "https://golang.com.br/blog/go-1-21/"
markdown_url: "https://golang.com.br/blog/go-1-21.MD"
description: "Go 1.21 trouxe builtins min/max/clear, log/slog estruturado, suporte WASI (WebAssembly), PGO ativado por padrao e toolchain management. Veja todas as mudancas."
date: "2023-08-08"
author: "Golang Brasil"
---

# Go 1.21: Novidades e Recursos

Go 1.21 trouxe builtins min/max/clear, log/slog estruturado, suporte WASI (WebAssembly), PGO ativado por padrao e toolchain management. Veja todas as mudancas.


# Go 1.21: O Que Há de Novo na Linguagem da Google

A versão 1.21 da linguagem Go foi lançada em 8 de agosto de 2023, trazendo consigo uma série de melhorias e novidades que visam otimizar o desenvolvimento, aprimorar a performance e expandir as capacidades da linguagem. Esta versão foca em estabilidade, usabilidade e refinamento das funcionalidades existentes. Vamos explorar as principais mudanças e como elas impactam o desenvolvimento em Go.

## Principais Novidades do Go 1.21

O Go 1.21 apresenta diversas novidades, mas destacaremos as mais significativas para o dia a dia de um desenvolvedor Go.

### 1. Profile Guided Optimization (PGO)

O Profile Guided Optimization (PGO) é, sem dúvida, a principal novidade desta versão. PGO é uma técnica de otimização de compilador que utiliza dados de perfil de execução reais para melhorar o desempenho do código. Em outras palavras, o compilador aprende como o seu programa se comporta em tempo de execução e otimiza o código com base nessas informações.

Antes do Go 1.21, o compilador Go realizava otimizações estáticas, analisando o código sem conhecimento do comportamento em tempo de execução. Com o PGO, o compilador pode tomar decisões mais inteligentes sobre inlining de funções, layout de memória e outras otimizações, resultando em um código mais rápido e eficiente.

**Como utilizar o PGO:**

1.  **Coletar o perfil:** Execute o seu programa com um workload representativo e gere um arquivo de perfil usando o comando `go test -cpuprofile=cpu.prof`.

    ```bash
    go test -cpuprofile=cpu.prof ./...
    ```

2.  **Construir o programa com o perfil:** Utilize a flag `-pgo` com o compilador `go build` para instruir o compilador a usar o perfil coletado.

    ```bash
    go build -pgo=cpu.prof .
    ```

    Se o perfil estiver no diretório raiz do módulo com o nome `default.pgo`, o compilador o utilizará automaticamente.

**Exemplo:**

Suponha que você tenha um programa que realiza cálculos complexos. Sem PGO, o compilador pode não ter informações suficientes para otimizar o código de forma eficaz. Com PGO, o compilador pode identificar as partes do código que são executadas com mais frequência e otimizá-las, resultando em um ganho significativo de desempenho.

```go
package main

import (
	"fmt"
	"time"
)

func fibonacci(n int) int {
	if n <= 1 {
		return n
	}
	return fibonacci(n-1) + fibonacci(n-2)
}

func main() {
	start := time.Now()
	result := fibonacci(40)
	elapsed := time.Since(start)

	fmt.Printf("Resultado: %d\n", result)
	fmt.Printf("Tempo de execução: %s\n", elapsed)
}
```

Para otimizar este código com PGO:

1.  Execute `go test -cpuprofile=cpu.prof .`
2.  Execute `go build -pgo=cpu.prof .`

A diferença de desempenho pode ser notável, especialmente para programas com gargalos de CPU.

**Considerações:**

*   O perfil deve ser representativo do workload real do seu programa. Perfis coletados com workloads diferentes podem levar a otimizações subótimas ou até mesmo a regressões de desempenho.
*   O PGO adiciona uma etapa extra ao processo de build, mas o ganho de desempenho geralmente compensa o custo adicional.
*   É recomendado monitorar o desempenho do seu programa após habilitar o PGO para garantir que as otimizações estão funcionando conforme o esperado.

### 2. Novas Funções na Biblioteca `slices`

O pacote `slices` recebeu novas funções que facilitam a manipulação de slices, tornando o código mais conciso e legível.

*   **`slices.Clone(s []T) []T`:** Cria uma cópia profunda de um slice. Isso é útil para evitar modificações indesejadas no slice original.

    ```go
    package main

    import (
    	"fmt"
    	"slices"
    )

    func main() {
    	original := []int{1, 2, 3}
    	copia := slices.Clone(original)
    	copia[0] = 10

    	fmt.Println("Original:", original) // Output: Original: [1 2 3]
    	fmt.Println("Cópia:", copia)   // Output: Cópia: [10 2 3]
    }
    ```

*   **`slices.Compare(s1, s2 []T) int`:** Compara dois slices e retorna um inteiro indicando a ordem lexicográfica. Retorna -1 se `s1 < s2`, 0 se `s1 == s2` e 1 se `s1 > s2`.

    ```go
    package main

    import (
    	"fmt"
    	"slices"
    )

    func main() {
    	s1 := []int{1, 2, 3}
    	s2 := []int{1, 2, 4}
    	s3 := []int{1, 2, 3}

    	fmt.Println(slices.Compare(s1, s2)) // Output: -1
    	fmt.Println(slices.Compare(s1, s3)) // Output: 0
    	fmt.Println(slices.Compare(s2, s1)) // Output: 1
    }
    ```

*   **`slices.DeleteFunc(s []T, del func(T) bool) []T`:** Remove todos os elementos de um slice que satisfazem uma determinada condição definida pela função `del`.

    ```go
    package main

    import (
    	"fmt"
    	"slices"
    )

    func main() {
    	numeros := []int{1, 2, 3, 4, 5, 6}
    	numeros = slices.DeleteFunc(numeros, func(n int) bool {
    		return n%2 == 0 // Remove números pares
    	})

    	fmt.Println(numeros) // Output: [1 3 5]
    }
    ```

*   **`slices.Insert(s []T, i int, v ...T) []T`:** Insere um ou mais elementos em um slice na posição `i`.

    ```go
    package main

    import (
    	"fmt"
    	"slices"
    )

    func main() {
    	numeros := []int{1, 2, 3}
    	numeros = slices.Insert(numeros, 1, 10, 20)

    	fmt.Println(numeros) // Output: [1 10 20 2 3]
    }
    ```

Estas funções simplificam tarefas comuns de manipulação de slices e reduzem a quantidade de código boilerplate que você precisa escrever. Consulte a documentação oficial para obter informações detalhadas sobre estas e outras funções no pacote `slices`: [https://pkg.go.dev/slices](https://pkg.go.dev/slices)

### 3. Novas Funções na Biblioteca `maps`

Similarmente ao pacote `slices`, o pacote `maps` também recebeu novas funções para auxiliar na manipulação de mapas.

*   **`maps.Clone(m map[K]V) map[K]V`:** Cria uma cópia profunda de um mapa.

    ```go
    package main

    import (
    	"fmt"
    	"maps"
    )

    func main() {
    	original := map[string]int{"a": 1, "b": 2}
    	copia := maps.Clone(original)
    	copia["a"] = 10

    	fmt.Println("Original:", original) // Output: Original: map[a:1 b:2]
    	fmt.Println("Cópia:", copia)   // Output: Cópia: map[a:10 b:2]
    }
    ```

*   **`maps.Copy(dst, src map[K]V)`:** Copia todos os pares chave-valor de um mapa de origem (`src`) para um mapa de destino (`dst`).  Se uma chave já existir no mapa de destino, o valor será substituído.

    ```go
    package main

    import (
    	"fmt"
    	"maps"
    )

    func main() {
    	destino := map[string]int{"a": 1, "b": 2}
    	origem := map[string]int{"b": 3, "c": 4}

    	maps.Copy(destino, origem)

    	fmt.Println("Destino:", destino) // Output: Destino: map[a:1 b:3 c:4]
    }
    ```

*   **`maps.DeleteFunc(m map[K]V, del func(K, V) bool)`:** Remove todos os pares chave-valor de um mapa que satisfazem uma determinada condição definida pela função `del`.

    ```go
    package main

    import (
    	"fmt"
    	"maps"
    )

    func main() {
    	idades := map[string]int{"Alice": 30, "Bob": 25, "Charlie": 35}
    	maps.DeleteFunc(idades, func(nome string, idade int) bool {
    		return idade < 30 // Remove pessoas com menos de 30 anos
    	})

    	fmt.Println(idades) // Output: map[Alice:30 Charlie:35]
    }
    ```

Estas funções simplificam a manipulação de mapas, tornando o código mais claro e menos propenso a erros. Consulte a documentação oficial para mais detalhes: [https://pkg.go.dev/maps](https://pkg.go.dev/maps)

### 4. `context.WithCancelCause`

A função `context.WithCancelCause` permite associar uma causa específica ao cancelamento de um contexto. Isso facilita a depuração e o tratamento de erros, pois o receptor do sinal de cancelamento pode determinar o motivo do cancelamento.

```go
package main

import (
	"context"
	"errors"
	"fmt"
	"time"
)

func main() {
	ctx, cancel := context.WithCancelCause(context.Background())

	go func() {
		time.Sleep(2 * time.Second)
		cancel(errors.New("timeout"))
	}()

	select {
	case <-ctx.Done():
		err := context.Cause(ctx)
		fmt.Println("Contexto cancelado:", err) // Output: Contexto cancelado: timeout
	case <-time.After(5 * time.Second):
		fmt.Println("Programa finalizado")
	}
}
```

Neste exemplo, o contexto é cancelado após 2 segundos com a causa "timeout". O receptor do sinal de cancelamento pode então acessar a causa usando `context.Cause(ctx)`.

### 5. Loop Variable Capture

O problema de captura de variáveis de loop em Goroutines foi atenuado nesta versão. Anteriormente, era comum encontrar erros onde Goroutines acessavam o valor da variável de loop após o loop ter terminado, resultando em valores inesperados. O Go 1.21 introduz uma mudança que mitiga este problema.

```go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	numeros := []int{1, 2, 3, 4, 5}

	for _, num := range numeros {
		wg.Add(1)
		go func(n int) {
			defer wg.Done()
			fmt.Println(n)
		}(num)
	}

	wg.Wait()
}
```

Neste exemplo, cada Goroutine recebe uma cópia do valor da variável `num` como argumento, garantindo que cada Goroutine trabalhe com o valor correto. Em versões anteriores do Go, sem a passagem explícita do valor para a Goroutine, todas as Goroutines poderiam acabar imprimindo o último valor de `num` (5). Esta alteração no comportamento padrão torna o código mais robusto e menos suscetível a erros sutis.

## Melhorias de Performance

Além do PGO, o Go 1.21 inclui outras melhorias de performance, como otimizações no garbage collector (GC) e no compilador. Essas melhorias podem resultar em tempos de execução menores e menor consumo de memória para seus programas. Os ganhos de performance podem variar dependendo do workload específico do seu aplicativo.

## Mudanças na Biblioteca Padrão

Além das novas funções nos pacotes `slices` e `maps`, o Go 1.21 traz outras mudanças e adições à biblioteca padrão:

*   **Novo pacote `cmp`:** Este pacote fornece funções para comparar valores de diferentes tipos. Ele é especialmente útil para implementar tipos genéricos que precisam ser comparados.
*   **Melhorias no pacote `net/http`:** Diversas melhorias foram feitas no pacote `net/http`, incluindo suporte para HTTP/2 Push e melhor tratamento de erros.
*   **Atualizações no pacote `time`:** O pacote `time` recebeu algumas atualizações, incluindo novas funções para formatar e analisar datas e horários.

Consulte as notas de lançamento para obter uma lista completa de todas as mudanças na biblioteca padrão: [https://go.dev/doc/go1.21](https://go.dev/doc/go1.21)

## Como Atualizar para o Go 1.21

Para atualizar para o Go 1.21, você pode usar o comando `go install`:

```bash
go install golang.org/dl/go1.21@latest
go1.21 download
go1.21 use
```

Este comando irá baixar e instalar a versão mais recente do Go 1.21. Após a instalação, você pode verificar a versão do Go usando o comando `go version`.

É importante notar que atualizar a versão do Go pode exigir a atualização de algumas dependências do seu projeto. Recomenda-se executar `go mod tidy` após a atualização para garantir que todas as dependências estejam atualizadas e compatíveis com o Go 1.21.

## Conclusão Prática

O Go 1.21 representa um passo importante na evolução da linguagem, trazendo melhorias significativas em performance, usabilidade e funcionalidade. O PGO é uma adição poderosa que pode otimizar o desempenho de seus programas, enquanto as novas funções nos pacotes `slices` e `maps` simplificam a manipulação de dados. As outras melhorias na biblioteca padrão e a mitigação do problema de captura de variáveis de loop tornam o Go 1.21 uma atualização valiosa para qualquer desenvolvedor Go.

Recomenda-se experimentar as novas funcionalidades e avaliar o impacto do PGO em seus projetos. A atualização para o Go 1.21 é um investimento que pode trazer benefícios significativos em termos de desempenho, produtividade e qualidade do código. Não deixe de consultar a documentação oficial para obter informações detalhadas sobre todas as mudanças e novidades do Go 1.21.
