---
title: "Go 1.17: Novidades e Recursos"
url: "https://golang.com.br/blog/go-1-17/"
markdown_url: "https://golang.com.br/blog/go-1-17.MD"
description: "Go 1.17 trouxe conversao slice-to-array, register-based calling convention (ate 15% mais rapido), pruned module graph e melhorias no go vet."
date: "2021-08-16"
author: "Golang Brasil"
---

# Go 1.17: Novidades e Recursos

Go 1.17 trouxe conversao slice-to-array, register-based calling convention (ate 15% mais rapido), pruned module graph e melhorias no go vet.


# Novidades do Go 1.17: Um mergulho nas melhorias e otimizações

A versão 1.17 da linguagem Go foi lançada em 16 de agosto de 2021, trazendo uma série de melhorias significativas em performance, sintaxe e na biblioteca padrão. Essa atualização foca em otimizar o desempenho do código gerado, simplificar a conversão de slices, e introduzir novas funcionalidades que facilitam o desenvolvimento e a manutenção de aplicações Go. As mudanças visam tornar o código Go mais eficiente, legível e fácil de trabalhar.

## Conversões de Slice: Simplificando o Código

Uma das adições mais notáveis do Go 1.17 é a simplificação das conversões de slice para array. Antes, converter um slice para um array requeria um processo complexo e, por vezes, ineficiente. A nova versão introduz uma forma mais direta e segura de realizar essa conversão, reduzindo a verbosidade do código e melhorando a performance.

### Conversão de Slice para Array Pointer

A principal mudança reside na possibilidade de converter um slice para um ponteiro para um array diretamente, contanto que o slice tenha capacidade suficiente. Isso é feito utilizando a seguinte sintaxe:

```go
package main

import "fmt"

func main() {
	s := []int{1, 2, 3}
	a := (*[3]int)(s) // Converte o slice 's' para um ponteiro para um array de 3 inteiros.
	fmt.Println(a)      // Imprime o array.
}
```

Neste exemplo, o slice `s` é convertido para um ponteiro para um array de 3 inteiros. É importante notar que o tamanho do array deve ser conhecido em tempo de compilação e deve corresponder ao comprimento do slice. Caso contrário, o código entrará em pânico em tempo de execução.

### Segurança e Considerações

Embora essa nova funcionalidade simplifique a conversão, é crucial garantir que o slice tenha capacidade suficiente para acomodar o tamanho do array desejado. Se o slice for menor que o tamanho do array, a conversão resultará em pânico.

```go
package main

import "fmt"

func main() {
	s := []int{1, 2}
	// a := (*[3]int)(s) // Isso causará pânico em tempo de execução, pois o slice tem comprimento 2 e o array tem tamanho 3.
	fmt.Println("Este código não será executado.")
}
```

Para evitar pânicos, é recomendado verificar o comprimento do slice antes de realizar a conversão.

```go
package main

import "fmt"

func main() {
	s := []int{1, 2, 3}
	if len(s) >= 3 {
		a := (*[3]int)(s)
		fmt.Println(a)
	} else {
		fmt.Println("Slice insuficiente para a conversão.")
	}
}
```

### Benefícios da Nova Conversão

Essa simplificação oferece diversos benefícios:

*   **Redução da verbosidade do código:** A conversão direta elimina a necessidade de criar um novo array e copiar os elementos do slice.
*   **Melhora da performance:** A conversão direta é mais eficiente do que a cópia manual de elementos.
*   **Maior legibilidade:** O código se torna mais claro e fácil de entender.

## Melhorias de Performance: Aprimorando a Eficiência do Código Gerado

O Go 1.17 introduz melhorias significativas no compilador, resultando em um código executável mais eficiente, especialmente em arquiteturas AMD64 (x86-64).  Essas otimizações focam na forma como as funções são chamadas e como os argumentos são passados, resultando em um ganho de performance notável em diversas aplicações.

### Passagem de Argumentos via Registradores

Uma das otimizações mais importantes é a utilização de registradores da CPU para passar argumentos para funções. Anteriormente, a maioria dos argumentos era passada através da pilha, o que envolvia operações de escrita e leitura na memória. Ao utilizar registradores, a passagem de argumentos se torna muito mais rápida, pois os registradores são muito mais acessíveis do que a memória.

Essa otimização se aplica tanto a funções Go quanto a chamadas para funções escritas em C (via cgo). O número de registradores utilizados para passar argumentos depende da arquitetura e do tipo dos argumentos. Em AMD64, um número significativo de argumentos inteiros e ponteiros pode ser passado via registradores, resultando em um ganho substancial de performance.

### Impacto na Performance

O impacto dessa otimização varia de acordo com a aplicação, mas em geral, observa-se uma melhora no desempenho em diversas áreas, incluindo:

*   **Redução do tempo de execução:** Aplicações que realizam muitas chamadas de função podem experimentar uma redução significativa no tempo de execução.
*   **Menor consumo de memória:** A utilização de registradores reduz a necessidade de alocar memória na pilha para armazenar argumentos.
*   **Melhora da latência:** A passagem de argumentos mais rápida contribui para uma menor latência em aplicações interativas.

### Medindo o Ganho de Performance

Para avaliar o ganho de performance proporcionado pelo Go 1.17, é recomendado realizar benchmarks comparando o desempenho do código antes e depois da atualização. A ferramenta `go test` oferece recursos para realizar benchmarks e comparar os resultados.

```bash
go test -bench=. ./...
```

Este comando executa todos os benchmarks no diretório atual e seus subdiretórios.  Após a atualização para o Go 1.17, execute os mesmos benchmarks e compare os resultados para verificar o ganho de performance.

### Exemplo de Benchmark

Considere o seguinte exemplo de um benchmark simples:

```go
package main

import (
	"testing"
)

func add(a, b int) int {
	return a + b
}

func BenchmarkAdd(b *testing.B) {
	for i := 0; i < b.N; i++ {
		add(i, i+1)
	}
}
```

Este benchmark mede o tempo necessário para executar a função `add` um grande número de vezes. Ao executar este benchmark antes e depois da atualização para o Go 1.17, você poderá observar uma melhora no desempenho devido à otimização da passagem de argumentos via registradores.

## Módulos Go: Versões Lazy Loading

O Go 1.17 introduz o conceito de "lazy loading" para módulos Go. Isso significa que o `go` toolchain não precisa mais baixar e analisar todos os módulos indiretos listados no arquivo `go.mod` durante operações como `go get`, `go build`, ou `go test`. Isso resulta em uma experiência significativamente mais rápida e eficiente, especialmente em projetos com muitas dependências.

### Funcionamento do Lazy Loading

Anteriormente, ao executar um comando como `go build`, o `go` toolchain baixava e analisava todos os módulos listados no arquivo `go.mod`, mesmo que alguns desses módulos não fossem realmente necessários para construir o programa. O lazy loading elimina essa necessidade, baixando e analisando apenas os módulos que são realmente utilizados durante a construção.

Isso é feito através de uma análise mais inteligente do código fonte para determinar quais módulos são realmente necessários. O `go` toolchain utiliza informações de importação e outras dependências para identificar os módulos que precisam ser baixados e analisados.

### Benefícios do Lazy Loading

O lazy loading oferece diversos benefícios:

*   **Redução do tempo de construção:** O tempo necessário para construir um programa é significativamente reduzido, especialmente em projetos com muitas dependências.
*   **Menor consumo de largura de banda:** Apenas os módulos necessários são baixados, reduzindo o consumo de largura de banda.
*   **Melhora da experiência do desenvolvedor:** O processo de desenvolvimento se torna mais rápido e eficiente, permitindo que os desenvolvedores se concentrem em escrever código em vez de esperar que as dependências sejam baixadas e analisadas.

### Impacto no Workflow

O lazy loading é habilitado por padrão no Go 1.17 e não requer nenhuma configuração adicional. Os desenvolvedores podem simplesmente continuar utilizando o `go` toolchain da mesma forma que antes, e o lazy loading será aplicado automaticamente.

Em alguns casos, pode ser necessário forçar o download e análise de todos os módulos, por exemplo, ao realizar uma análise estática completa do código. Nesses casos, pode-se utilizar a flag `-mod=mod` com os comandos `go build`, `go test`, etc.

```bash
go build -mod=mod ./...
```

Essa flag instrui o `go` toolchain a baixar e analisar todos os módulos listados no arquivo `go.mod`, desabilitando o lazy loading.

## Mudanças na Biblioteca Padrão

Embora o Go 1.17 não introduza mudanças radicais na biblioteca padrão, algumas adições e modificações sutis merecem destaque.

### Pacote `net/http`

*   **Suporte a HTTP/2 Push:** O pacote `net/http` recebeu algumas melhorias no suporte a HTTP/2 Push, permitindo que os servidores enviem recursos para os clientes antes que eles sejam explicitamente solicitados. Isso pode melhorar significativamente o desempenho de aplicações web.

### Pacote `crypto/tls`

*   **Melhorias na Negociação de Protocolos:** O pacote `crypto/tls` recebeu algumas melhorias na negociação de protocolos TLS, permitindo que os servidores e clientes negociem protocolos mais modernos e seguros.

### Pacote `os`

*   **Função `DirFS`:** O pacote `os` agora inclui a função `DirFS`, que permite criar um sistema de arquivos virtual a partir de um diretório no sistema de arquivos real. Isso pode ser útil para testar aplicações que interagem com o sistema de arquivos.

```go
package main

import (
	"fmt"
	"io/fs"
	"os"
)

func main() {
	// Cria um sistema de arquivos virtual a partir do diretório atual.
	fsys := os.DirFS(".")

	// Abre um arquivo no sistema de arquivos virtual.
	file, err := fsys.Open("main.go")
	if err != nil {
		fmt.Println(err)
		return
	}

	// Imprime o nome do arquivo.
	fmt.Println(file.Name())
}
```

## Como Atualizar para o Go 1.17

A atualização para o Go 1.17 é um processo relativamente simples. Existem diversas formas de realizar a atualização, dependendo do sistema operacional e da forma como o Go foi instalado.

### Utilizando o Gerenciador de Pacotes

Em sistemas Linux que utilizam um gerenciador de pacotes como APT ou Yum, a atualização pode ser feita através do gerenciador de pacotes.

```bash
# Exemplo utilizando APT (Debian, Ubuntu)
sudo apt update
sudo apt install golang
```

```bash
# Exemplo utilizando Yum (CentOS, Fedora)
sudo yum update golang
```

É importante verificar se o gerenciador de pacotes está configurado para utilizar os repositórios oficiais do Go, para garantir que a versão mais recente seja instalada.

### Utilizando o `go install`

Outra forma de atualizar é utilizando o comando `go install`. Este método requer que o Go já esteja instalado no sistema.

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

Esses comandos baixam e instalam a versão 1.17 do Go e a definem como a versão padrão.

### Download e Instalação Manual

Também é possível baixar os binários do Go 1.17 diretamente do site oficial e instalar manualmente. Este método é recomendado para usuários que desejam ter controle total sobre o processo de instalação.

1.  Acesse o site oficial do Go: [https://go.dev/dl/](https://go.dev/dl/)
2.  Baixe o pacote correspondente ao seu sistema operacional e arquitetura.
3.  Extraia o pacote para um diretório de sua escolha (por exemplo, `/usr/local/go`).
4.  Configure as variáveis de ambiente `GOROOT` e `PATH` para apontar para o diretório de instalação do Go.

```bash
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
```

Após a atualização, é importante verificar se a instalação foi bem-sucedida.

```bash
go version
```

Este comando deve exibir a versão do Go instalada, que deve ser 1.17.

## Conclusão

O Go 1.17 representa um passo importante na evolução da linguagem, trazendo melhorias significativas em performance, sintaxe e na biblioteca padrão. As otimizações no compilador, a simplificação das conversões de slice e a introdução do lazy loading para módulos contribuem para um desenvolvimento mais eficiente e uma melhor experiência para os desenvolvedores.  A atualização para o Go 1.17 é altamente recomendada para todos os projetos Go, pois oferece ganhos de performance e simplificações que podem impactar positivamente a produtividade e a qualidade do código. Recomenda-se consultar as notas de lançamento oficiais em [https://go.dev/doc/go1.17](https://go.dev/doc/go1.17) para uma visão completa de todas as mudanças e adições.
