
GOPATH — um jeito de trabalhar que a própria linguagem abandonou. Reescrevemos como um hello world de verdade no Ubuntu, com a versão atual e com módulos.Este é o caminho mais curto entre um Ubuntu limpo e o seu primeiro programa em Go rodando. Leva uns dez minutos, e no fim você sai com um binário único que roda em qualquer Linux — sem interpretador, sem máquina virtual, sem dependência para instalar no servidor.
Por que Go, em duas frases
O Go foi desenhado no Google em 2007 porque o C++ demorava demais para compilar e a concorrência dava trabalho demais. O resultado: compila em segundos, tem concorrência embutida na linguagem e entrega um binário estático. É por isso que Docker, Kubernetes, Terraform e Prometheus são escritos nele. A história completa está em A história da linguagem Go.
Installing on Ubuntu
Existem três caminhos. O tarball oficial é o recomendado — o pacote do apt costuma ficar uma ou duas versões atrás, e no Go isso importa porque a linguagem lança a cada seis meses.
# descobre a versão atual sem abrir o navegador
VER=$(curl -fsSL 'https://go.dev/VERSION?m=text' | head -n1)
echo "$VER"
# baixa e instala no lugar canônico
cd /tmp
curl -fLO "https://go.dev/dl/${VER}.linux-amd64.tar.gz"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "${VER}.linux-amd64.tar.gz"
Repare no rm -rf /usr/local/go antes de extrair: é o passo que a documentação oficial exige e que quase todo tutorial esquece. Extrair por cima de uma instalação antiga mistura arquivos de duas versões e gera erro difícil de diagnosticar.
Agora o PATH. Para valer no sistema inteiro e sobreviver a novos usuários:
echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee /etc/profile.d/go.sh
source /etc/profile.d/go.sh
go version
Se apareceu algo como go version go1.27.1 linux/amd64, está pronto. Se o comando não foi encontrado, o source acima resolve na sessão atual — nas próximas ele carrega sozinho.
Em máquina ARM, como um Raspberry Pi, troque linux-amd64 by linux-arm64.
As alternativas, e quando usá-las
# snap — versão recente, atualiza sozinho
sudo snap install go --classic
# apt — mais simples, versão mais velha
sudo apt install golang-go
The apt serve se você só precisa compilar algo de terceiro e não se importa com a versão. Para desenvolver, fique no tarball.
Hello, world
Antes de qualquer estrutura de projeto, veja a linguagem nua. Crie ola.go:
package main
import "fmt"
func main() {
fmt.Println("Olá, mundo!")
}
go run ola.go
The go run compila e executa em memória, sem deixar binário — é o modo de experimentar. Três coisas para reparar: todo programa executável começa em package main; a função de entrada é func main(); e o import é obrigatório e não pode sobrar. Se você importar um pacote e não usar, o Go se recusa a compilar. É rígido de propósito.
Agora do jeito certo: um módulo
Na prática ninguém trabalha com arquivo solto. O Go organiza projeto em módulos desde a versão 1.11, e essa é a mudança que aposentou o velho GOPATH deste post em 2017:
mkdir ~/ola && cd ~/ola
go mod init exemplo.com/ola
Isso cria o go.mod, que declara o nome do módulo e a versão da linguagem. Agora um programa um pouco mais interessante — crie main.go:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
fmt.Print("Qual o seu nome? ")
leitor := bufio.NewReader(os.Stdin)
nome, err := leitor.ReadString('n')
if err != nil {
fmt.Fprintln(os.Stderr, "erro ao ler a entrada:", err)
os.Exit(1)
}
nome = strings.TrimSpace(nome)
if nome == "" {
fmt.Println("Você não digitou nada.")
return
}
fmt.Printf("Olá, %s! Bem-vindo ao Go.n", nome)
}
go run .
Aqui aparece a marca registrada da linguagem: o if err != nil. Em Go não existe exceção — toda função que pode falhar devolve o erro junto com o resultado, e você é obrigado a decidir o que fazer com ele. É verboso, é criticado, e é intencional: o caminho do erro fica visível no código, não escondido num catch distante.
Gerando o binário
Esta é a parte que vende a linguagem para quem administra servidor:
go build -o ola
ls -lh ola
./ola
O arquivo ola é um executável completo. Copie para outro Linux e ele roda — não é preciso instalar o Go lá, nem runtime, nem biblioteca. E dá para compilar para outro sistema sem sair do seu:
GOOS=linux GOARCH=arm64 go build -o ola-arm # Raspberry Pi
GOOS=windows GOARCH=amd64 go build -o ola.exe # Windows
GOOS=darwin GOARCH=arm64 go build -o ola-mac # Mac com Apple Silicon
Compilação cruzada em uma variável de ambiente, sem toolchain extra. É por isso que tanta ferramenta de linha de comando moderna é distribuída como um binário por plataforma.
Usando uma dependência
go get github.com/fatih/color
package main
import "github.com/fatih/color"
func main() {
color.Green("Olá, mundo!")
color.New(color.FgYellow, color.Bold).Println("agora em amarelo e negrito")
}
go mod tidy # ajusta o go.mod: adiciona o que falta, remove o que sobra
go run .
The go.sum, criado automaticamente, guarda o hash de cada dependência — é o que garante que a versão baixada amanhã é byte a byte a mesma de hoje. Versione os dois arquivos, go.mod and go.sum, junto com o código.
Um gostinho de concorrência
Não dá para apresentar Go sem mostrar a goroutine, que é o motivo de a linguagem ter ganhado a infraestrutura:
package main
import (
"fmt"
"net/http"
"time"
)
func checar(url string, resultado chan<- string) {
inicio := time.Now()
resp, err := http.Get(url)
if err != nil {
resultado <- fmt.Sprintf("%-28s ERRO: %v", url, err)
return
}
defer resp.Body.Close()
resultado <- fmt.Sprintf("%-28s %s em %v", url, resp.Status, time.Since(inicio).Round(time.Millisecond))
}
func main() {
sites := []string{
"https://www.linuxpro.com.br",
"https://go.dev",
"https://kernel.org",
}
resultado := make(chan string)
for _, s := range sites {
go checar(s, resultado) // dispara os três ao mesmo tempo
}
for range sites {
fmt.Println(<-resultado) // recebe conforme forem chegando
}
}
go run .
Os três sites são consultados em paralelo, e o total demora o tempo do mais lento, não a soma dos três. Isso é uma palavra — go — e um canal. Sem biblioteca, sem pool de threads, sem callback.
As ferramentas que já vêm juntas
go fmt ./... # formata no padrão oficial; não há debate de estilo em Go
go vet ./... # aponta erro provável que compila mesmo assim
go test ./... # roda os testes
go doc fmt.Println # documentação sem sair do terminal
go clean -cache # limpa o cache de build quando algo fica estranho
The go fmt merece destaque: a linguagem tem a estilo oficial, aplicado por ferramenta. Isso encerrou, de saída, a discussão sobre tabulação e chaves que consome tempo em outras comunidades.
Várias versões na mesma máquina
Quando um projeto está preso numa versão antiga, o próprio Go resolve — sem gerenciador externo:
go install golang.org/dl/go1.26@latest
go1.26 download
go1.26 version
E, desde a 1.21, existe algo ainda melhor: se o go.mod do projeto pedir uma versão que você não tem, o GOTOOLCHAIN baixa a correta na hora do build, sozinho.
Por onde seguir
- A Tour of Go — o tutorial oficial, interativo, roda no navegador. É a melhor porta de entrada.
- Effective Go — como escrever código que parece Go, e não Java traduzido.
- Aqui no blog: A história da linguagem Go, o howto de instalação detalhado and as principais linguagens de programação.
- Feito em Go, para estudar código real: go-postfixadmin and Gogs.
Dez minutos, um binário estático e um gopher azul. Bom começo.