---
title: "Go 1.18: Novidades e Recursos"
url: "https://golang.com.br/blog/go-1-18/"
markdown_url: "https://golang.com.br/blog/go-1-18.MD"
description: "Go 1.18 foi a maior release da historia do Go: generics (type parameters), fuzzing nativo para testes, go workspace para multi-module e 20% mais rapido no ARM."
date: "2022-03-15"
author: "Golang Brasil"
---

# Go 1.18: Novidades e Recursos

Go 1.18 foi a maior release da historia do Go: generics (type parameters), fuzzing nativo para testes, go workspace para multi-module e 20% mais rapido no ARM.


# Go 1.18: As Novidades da Linguagem

A versão 1.18 do Go, lançada em 15 de março de 2022, trouxe mudanças significativas para a linguagem, com destaque para a introdução de generics, workspaces e melhorias de performance. Esta atualização representa um marco importante na evolução do Go, expandindo suas capacidades e oferecendo novas ferramentas para os desenvolvedores.

## Generics: Programação Genérica no Go

A principal novidade do Go 1.18 é, sem dúvida, a introdução de generics (tipos genéricos).  Generics permitem escrever código que pode operar com diferentes tipos de dados sem a necessidade de duplicação de código ou uso de `interface{}` (a interface vazia) com type assertions.  Essa funcionalidade promove maior reutilização, segurança de tipos e legibilidade.

### Tipos Genéricos

Um tipo genérico é definido com um parâmetro de tipo, que é um placeholder para um tipo específico que será fornecido posteriormente. A sintaxe para declarar um tipo genérico usa colchetes `[]` para envolver o(s) parâmetro(s) de tipo.

```go
package main

import "fmt"

// Tipo genérico List, parametrizado com o tipo T.
type List[T any] struct {
	head *node[T]
	tail *node[T]
}

type node[T any] struct {
	val  T
	next *node[T]
}

func (l *List[T]) Add(val T) {
	n := &node[T]{val: val}
	if l.head == nil {
		l.head = n
		l.tail = n
	} else {
		l.tail.next = n
		l.tail = n
	}
}

func (l *List[T]) Print() {
	curr := l.head
	for curr != nil {
		fmt.Println(curr.val)
		curr = curr.next
	}
}

func main() {
	// Cria uma lista de inteiros.
	intList := List[int]{}
	intList.Add(1)
	intList.Add(2)
	intList.Add(3)
	intList.Print()

	// Cria uma lista de strings.
	stringList := List[string]{}
	stringList.Add("hello")
	stringList.Add("world")
	stringList.Print()
}
```

Neste exemplo, `List[T]` é um tipo genérico que representa uma lista ligada.  O tipo `T` é um parâmetro de tipo, que pode ser substituído por qualquer tipo concreto quando a lista é instanciada.  `any` é uma constraint que significa "qualquer tipo".

### Funções Genéricas

Funções genéricas são declaradas de forma semelhante aos tipos genéricos, com parâmetros de tipo entre colchetes antes dos parâmetros da função.

```go
package main

import "fmt"

// Função genérica que retorna o maior valor entre dois valores do mesmo tipo.
func Max[T comparable](a, b T) T {
	if a > b {
		return a
	}
	return b
}

func main() {
	fmt.Println(Max[int](10, 20))    // Imprime 20
	fmt.Println(Max[float64](3.14, 2.71)) // Imprime 3.14
	fmt.Println(Max[string]("apple", "banana")) // Imprime banana
}
```

Neste exemplo, `Max[T comparable](a, b T) T` é uma função genérica que recebe dois valores do mesmo tipo e retorna o maior deles. A constraint `comparable` significa que o tipo `T` deve ser comparável usando os operadores `>`, `<`, `>=`, `<=` e `==`.  Se tentarmos usar `Max` com um tipo que não é comparável (por exemplo, um struct sem operadores de comparação definidos), o compilador gerará um erro.

### Type Constraints

Type constraints (restrições de tipo) especificam quais tipos são permitidos para um parâmetro de tipo.  As constraints são definidas usando interfaces.

```go
package main

import "fmt"

// Interface que define uma constraint para tipos que podem ser somados.
type Summable interface {
	int | int8 | int16 | int32 | int64 | float32 | float64
}

// Função genérica que soma dois valores do mesmo tipo Summable.
func Sum[T Summable](a, b T) T {
	return a + b
}

func main() {
	fmt.Println(Sum[int](10, 20))    // Imprime 30
	fmt.Println(Sum[float64](3.14, 2.71)) // Imprime 5.85
	// Sum[string]("hello", "world") // Erro de compilação: string não implementa Summable
}
```

Aqui, a interface `Summable` define uma constraint que permite apenas tipos numéricos inteiros e de ponto flutuante.  A função `Sum` só pode ser chamada com valores desses tipos. Tentar usá-la com `string` resultará em um erro de compilação.

### Type Inference

O Go 1.18 introduz a inferência de tipo para funções genéricas. Em muitos casos, o compilador pode inferir os tipos dos parâmetros genéricos com base nos argumentos da função, eliminando a necessidade de especificar explicitamente os tipos entre colchetes.

```go
package main

import "fmt"

func Print[T any](s []T) {
	for _, v := range s {
		fmt.Println(v)
	}
}

func main() {
	// O compilador infere que T é int.
	Print([]int{1, 2, 3})

	// O compilador infere que T é string.
	Print([]string{"a", "b", "c"})
}
```

Neste exemplo, não precisamos especificar `Print[int]` ou `Print[string]`. O compilador infere o tipo `T` com base no tipo do slice passado como argumento.

### Mais informações sobre Generics

A documentação oficial sobre generics no Go pode ser encontrada aqui: [https://go.dev/tour/generics/1](https://go.dev/tour/generics/1) e [https://go.dev/ref/spec#Type_parameters](https://go.dev/ref/spec#Type_parameters).

## Workspaces

Go workspaces permitem trabalhar com vários módulos Go simultaneamente.  Anteriormente, cada módulo Go precisava ser gerenciado individualmente, o que podia ser complicado em projetos grandes que dependiam de vários módulos locais.  Workspaces simplificam esse processo, permitindo que você defina um diretório raiz que contenha vários módulos.

### Criando um Workspace

Para criar um workspace, use o comando `go work init`.

```bash
mkdir myproject
cd myproject
go work init
```

Isso cria um arquivo `go.work` no diretório `myproject`.  O arquivo `go.work` contém informações sobre os módulos incluídos no workspace.

### Adicionando Módulos ao Workspace

Para adicionar módulos ao workspace, use o comando `go work use`.

```bash
go work use ./module1
go work use ./module2
```

Isso adiciona os módulos `module1` e `module2` ao workspace.  O arquivo `go.work` será atualizado para refletir os módulos adicionados.

### Benefícios dos Workspaces

*   **Gerenciamento Simplificado de Múltiplos Módulos:** Facilita o desenvolvimento em projetos com várias dependências de módulos locais.
*   **Testes Integrados:** Permite testar e construir todos os módulos no workspace como um único projeto.
*   **Compartilhamento de Dependências:** Garante que todos os módulos no workspace usem as mesmas versões de dependências.

### Exemplo de Arquivo `go.work`

```
go 1.18

use (
	./module1
	./module2
)
```

Este arquivo `go.work` indica que o workspace contém os módulos `module1` e `module2`.  Ao executar comandos Go (como `go build`, `go test`, `go run`) no diretório do workspace, o Go considerará todos os módulos listados no arquivo `go.work`.

### Mais informações sobre Workspaces

A documentação oficial sobre workspaces pode ser encontrada aqui: [https://go.dev/doc/tutorial/workspaces](https://go.dev/doc/tutorial/workspaces).

## Performance Improvements

O Go 1.18 introduziu melhorias de performance significativas, particularmente para arquiteturas ARM64 (Apple Silicon).

### Melhorias na Implementação do Garbage Collector (GC)

O garbage collector (GC) foi otimizado para reduzir a latência e o uso de CPU, resultando em melhorias de performance em aplicações que alocam e desalocam memória frequentemente.

### Otimizações para Arquitetura ARM64

A versão 1.18 inclui otimizações específicas para a arquitetura ARM64, como a utilização de instruções SIMD (Single Instruction, Multiple Data) para operações vetoriais. Isso resulta em um desempenho significativamente melhor em dispositivos como os Macs com chips M1.

### Impacto nas Aplicações

As melhorias de performance no Go 1.18 podem resultar em:

*   **Menor latência:** Aplicações respondem mais rapidamente às solicitações.
*   **Menor uso de CPU:** Redução do consumo de energia e melhor escalabilidade.
*   **Maior throughput:** Capacidade de processar mais solicitações por unidade de tempo.

Embora os ganhos de performance variem dependendo da aplicação, muitas aplicações Go podem se beneficiar dessas otimizações sem a necessidade de alterações no código.

## Mudanças na Biblioteca Padrão

O Go 1.18 também trouxe algumas mudanças e adições à biblioteca padrão.

### Função `cmp.Compare`

O pacote `cmp` (novo pacote) introduz a função `Compare`, que simplifica a comparação de valores.

```go
package main

import (
	"cmp"
	"fmt"
)

func main() {
	fmt.Println(cmp.Compare(10, 20))    // Imprime -1 (10 < 20)
	fmt.Println(cmp.Compare(20, 10))    // Imprime 1 (20 > 10)
	fmt.Println(cmp.Compare(10, 10))    // Imprime 0 (10 == 10)
	fmt.Println(cmp.Compare("apple", "banana")) // Imprime -1 ("apple" < "banana")
}
```

A função `cmp.Compare` retorna:

*   `-1` se o primeiro argumento for menor que o segundo.
*   `1` se o primeiro argumento for maior que o segundo.
*   `0` se os argumentos forem iguais.

Essa função é especialmente útil para implementar funções de ordenação genéricas.

### Pacote `net/netip`

O novo pacote `net/netip` fornece tipos de dados mais eficientes para representar endereços IP.  O tipo `netip.Addr` é uma representação compacta de um endereço IP, que ocupa menos memória do que o tipo `net.IP` anterior.

```go
package main

import (
	"fmt"
	"net/netip"
)

func main() {
	addr, err := netip.ParseAddr("192.168.1.1")
	if err != nil {
		panic(err)
	}
	fmt.Println(addr) // Imprime 192.168.1.1

	addr, err = netip.ParseAddr("2001:db8::1")
	if err != nil {
		panic(err)
	}
	fmt.Println(addr) // Imprime 2001:db8::1
}
```

O pacote `net/netip` também inclui funções para trabalhar com prefixos de rede e outras operações relacionadas a endereços IP.

### Melhorias no pacote `testing`

O pacote `testing` recebeu algumas melhorias, incluindo a capacidade de usar `-test.fuzz` com valores de sementes e o suporte a um novo método `T.Setenv` para definir variáveis de ambiente temporariamente para um teste.

```go
package main

import (
	"os"
	"testing"
)

func TestMyFunction(t *testing.T) {
	// Define uma variável de ambiente temporariamente para este teste.
	t.Setenv("MY_VAR", "my_value")

	// Obtém o valor da variável de ambiente.
	value := os.Getenv("MY_VAR")

	// Verifica se o valor está correto.
	if value != "my_value" {
		t.Errorf("Expected MY_VAR to be 'my_value', but got '%s'", value)
	}
}
```

## Como Atualizar para Go 1.18

Para atualizar para o Go 1.18, use o seguinte comando:

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

Esses comandos instalarão a versão 1.18 do Go e a definirão como a versão padrão.  Verifique a instalação executando `go version`.

```bash
go version
```

O comando deve retornar `go version go1.18 <sistema operacional>/<arquitetura>`.

## Conclusão

O Go 1.18 representa um avanço significativo para a linguagem, com a introdução de generics, workspaces e melhorias de performance.  Generics oferecem maior flexibilidade e segurança de tipos, workspaces simplificam o gerenciamento de projetos com múltiplos módulos, e as melhorias de performance resultam em aplicações mais rápidas e eficientes.  As mudanças na biblioteca padrão também fornecem novas ferramentas e melhorias para os desenvolvedores Go.  A atualização para o Go 1.18 é altamente recomendada para aproveitar todos esses benefícios.  Consulte as notas de lançamento oficiais para uma lista completa de mudanças e detalhes adicionais: [https://go.dev/doc/go1.18](https://go.dev/doc/go1.18).
