Carregando
Todos os artigos
Programação 16 min de leitura

Seu Primeiro Programa em Go: Um Guia Visual e Prático

Escreva, compile e rode o seu primeiro programa em Go e entenda cada linha: package main, import, func main, fmt.Println e Printf, go run vs. go build, os erros rígidos do compilador, gofmt, leitura do teclado, códigos de saída, compilação cruzada, medições reais e exercícios.

nbkhope
Nesta página

O Go (muitas vezes chamado de Golang) foi criado no Google para ser simples, rápido de compilar e agradável de usar em projetos grandes. Ele move o Docker, o Kubernetes e boa parte da nuvem. E o Olá, Mundo dele tem só sete linhas.

Neste guia você vai escrever, rodar e compilar o seu primeiro programa em Go e depois desmontá-lo linha por linha. Você vai imprimir textos e números, conhecer o compilador famoso por ser rígido (ele se recusa a compilar código com um import que não é usado!), deixar o gofmt formatar o seu código, ler dados do teclado e gerar programas para outros sistemas operacionais com um único comando. Exercícios fecham o artigo.

Todas as saídas e medições abaixo vêm de execuções reais com o Go 1.22 no Windows. As mensagens do compilador são em inglês; vamos traduzindo as importantes.

Preparando tudo

Baixe o Go em go.dev/dl (há instaladores para Windows, macOS e Linux; no Linux, veja também como instalar o Go no Linux) e confira num terminal:

$ go version
go version go1.22.5 windows/amd64

O código Go vive em módulos: uma pasta com um arquivo go.mod que dá nome ao projeto. Crie uma pasta e um módulo para o seu primeiro programa:

1$ mkdir ola
2$ cd ola
3$ go mod init ola
4go: creating new go.mod: module ola

Olá, Mundo!

Crie um arquivo chamado ola.go nessa pasta:

1package main
2
3import "fmt"
4
5func main() {
6	fmt.Println("Olá, Mundo!")
7}

Rode:

$ go run .
Olá, Mundo!

O go run . compila o programa da pasta atual e o roda na hora. Parabéns, você é um programador de Go! Agora vamos ver o que cada linha faz.

A anatomia do Olá, Mundo em Go. package main diz que o arquivo pertence ao pacote main, aquele que vira um programa executável. import "fmt" traz o pacote fmt, de format, formatar, que imprime texto. func main() { declara a função main, onde o programa começa; func é a palavra-chave das funções. fmt.Println("Olá, Mundo!") chama a função Println do pacote fmt: Println começa com letra maiúscula porque é exportada, e o ln quer dizer que ela pula uma linha; "Olá, Mundo!" é uma string. Não há ponto e vírgula: o Go coloca um no fim de cada linha para você. A chave } fecha a função
  • package main: todo arquivo Go começa dizendo a qual pacote pertence. O pacote chamado main é especial: é ele que vira um programa executável.
  • import "fmt": traz o pacote fmt (de format, formatar), da biblioteca padrão do Go, que cuida da impressão.
  • func main(): declara uma função chamada main. Como em C e C++, todo programa em Go começa nela. func é a palavra-chave das funções, e o corpo vai entre { e }.
  • fmt.Println("Olá, Mundo!"): chama a função Println do pacote fmt. Ela imprime os argumentos e pula uma linha (o ln, de line).
  • Sem ponto e vírgula: o Go coloca um automaticamente no fim de cada linha. Já falamos disso.

Repare que main aparece em dois lugares: o pacote main e a função main. Um programa executável em Go precisa dos dois.

go run vs. go build

O go run é prático enquanto você escreve o código, mas ele compila o programa numa pasta temporária toda vez. O go build gera um executável que fica:

$ go build
$ ./ola
Olá, Mundo!

No Windows, o go build cria o ola.exe (rode com .\ola.exe no PowerShell). Esse único arquivo é o programa inteiro: o computador que o roda não precisa ter o Go instalado.

go run vs go build. O go run compila o programa numa pasta temporária, roda e joga o executável fora: bom enquanto você escreve o código. O go build compila uma vez num executável que fica, ola.exe ou ola: bom para distribuir e publicar. Medido para este artigo com o Go 1.22 no Windows, mediana de 7 execuções e depois mediana de 3 rodadas: o go run levou 1.506 milissegundos; rodar o ola.exe já compilado levou 25 milissegundos. O primeiro build, com o cache vazio, levou 8.719 milissegundos, porque o Go compila uma vez os pacotes da biblioteca padrão de que precisa; um novo build com o cache levou 1.070 milissegundos

Medimos os dois neste computador:

O quêTempo
Primeiro go build (cache de build vazio)8.719 ms
Build de novo (cache cheio)1.070 ms
go run .1.506 ms
Rodar o ola.exe já compilado25 ms

O primeiro build é o lento porque o Go também compila os pacotes da biblioteca padrão que o seu programa usa e os guarda no cache. Depois disso, os builds levam cerca de um segundo, e o programa pronto começa em poucas dezenas de milissegundos. (O antivírus do Windows deixa cada passo mais lento aqui; no Linux, os mesmos passos costumam ser mais rápidos.)

Qual é o tamanho do programa?

Qual é o tamanho de um Olá, Mundo em Go? Tamanhos dos executáveis medidos com o Go 1.22: ola.exe para Windows, 1.990.144 bytes, cerca de 1,9 MB; o mesmo programa sem as informações de depuração, go build -ldflags="-s -w", 1.333.248 bytes; para Linux, 1.898.161 bytes; para macOS com Apple Silicon, 2.029.586 bytes. Os executáveis do Go são ligados estaticamente: o runtime do Go, o coletor de lixo e o pacote fmt vão todos dentro do arquivo, então ele roda num computador sem mais nada instalado

Cerca de 1,9 MB para um Olá, Mundo. Parece muito, mas os programas em Go são ligados estaticamente: o runtime do Go, o coletor de lixo e todos os pacotes que você usa ficam dentro desse único arquivo. Copie-o para outro computador com o mesmo sistema operacional e ele simplesmente roda.

Imprimindo: Println, Print e Printf

O pacote fmt tem três funções de impressão que você vai usar o tempo todo:

1package main
2
3import "fmt"
4
5func main() {
6	fmt.Println("Olá,", "Gopher!", 2024)
7	fmt.Print("Sem pular linha. ")
8	fmt.Print("Mesma linha.\n")
9	fmt.Printf("%s tem %d anos e %.2f m de altura\n", "Ada", 36, 1.65)
10	fmt.Printf("%v %v %v\n", 42, "texto", true)
11	fmt.Printf("%T %T %T\n", 42, "texto", 3.14)
12	fmt.Println(7/2, 7.0/2, 7%2)
13}
1Olá, Gopher! 2024
2Sem pular linha. Mesma linha.
3Ada tem 36 anos e 1.65 m de altura
442 texto true
5int string float64
63 3.5 1
  • Println imprime os argumentos separados por espaços e pula uma linha.
  • Print não pula linha (use \n, a sequência de escape de nova linha, quando quiser).
  • Printf (print formatted, imprimir formatado) preenche verbos num modelo: %s para string, %d para número inteiro, %.2f para decimal com 2 casas, %v para qualquer valor no formato padrão e %T para o tipo de um valor.

A última linha é clássica: dividir dois números inteiros com / joga fora o resto (7/2 dá 3), um decimal o mantém (7.0/2 dá 3.5), e o % dá o resto (1). (O Go usa ponto, não vírgula, nos números.)

O compilador rígido do Go

O Go é famoso por se recusar a compilar código que a maioria das linguagens só avisaria. Um import sem uso é erro:

1package main
2
3import (
4	"fmt"
5	"os"
6)
7
8func main() {
9	fmt.Println("Olá, Mundo!")
10}
$ go run .
# ola
.\main.go:5:2: "os" imported and not used

("O os foi importado e não foi usado.") Uma variável sem uso também:

1package main
2
3import "fmt"
4
5func main() {
6	mensagem := "Olá, Mundo!"
7	fmt.Println("Oi!")
8}
$ go run .
# ola
.\main.go:6:2: mensagem declared and not used
As regras do compilador do Go que surpreendem os iniciantes, com as mensagens reais do Go 1.22. Import sem uso é erro: "os" imported and not used. Variável sem uso é erro: mensagem declared and not used. A chave de abertura fica na mesma linha: colocar a { na linha seguinte dá syntax error: unexpected semicolon or newline before {. Letras maiúsculas importam: fmt.println dá undefined: fmt.println, porque só nomes que começam com letra maiúscula, como Println, são exportados por um pacote. Um programa executável precisa de package main: senão o go run diz package ola is not a main package. Por que tanto rigor? Imports e variáveis sobrando deixam o build lento e escondem erros, então o Go mantém o código limpo na marra

As mensagens seguem o padrão de sempre: arquivo:linha:coluna: problema. (No macOS e no Linux o caminho aparece como ./main.go.) Os criadores do Go fizeram esses erros de propósito: imports sem uso deixam lento o build de programas grandes, e variáveis sem uso muitas vezes indicam um bug. O conserto é simples: apague o que você não usa. Enquanto experimenta, dá para calar uma variável sem uso atribuindo-a ao identificador vazio, _ = mensagem.

Onde fica a chave, e os pontos e vírgulas invisíveis

Os comandos do Go terminam com ponto e vírgula, mas você nunca os digita: o compilador coloca um no fim de toda linha que parece terminada. Isso tem uma consequência. Coloque a chave de abertura numa linha sozinha:

1package main
2
3import "fmt"
4
5func main()
6{
7	fmt.Println("Olá, Mundo!")
8}
$ go run .
# ola
.\main.go:6:1: syntax error: unexpected semicolon or newline before {

A linha func main() parecia terminada, então o Go colocou um ponto e vírgula depois dela, e aí a { na linha seguinte não fez sentido ("ponto e vírgula ou nova linha inesperados antes da {"). No Go, a chave de abertura fica sempre na mesma linha.

Letras maiúsculas importam

1package main
2
3import "fmt"
4
5func main() {
6	fmt.println("Olá, Mundo!")
7}
$ go run .
# ola
.\main.go:6:6: undefined: fmt.println

No Go, um nome que começa com letra maiúscula é exportado: outros pacotes podem usá-lo. O Println é exportado; um println minúsculo no fmt seria privado do pacote fmt. Esse é todo o sistema de visibilidade do Go: nada de palavras-chave public ou private, só a primeira letra.

Tem que ser package main

Se o pacote tiver outro nome, o Go trata a pasta como uma biblioteca, algo que outros programas importam, e não um programa que dá para rodar:

$ go run .
package ola is not a main package

Deixe o gofmt formatar o seu código

O Go vem com um formatador oficial, e quase todo projeto em Go o usa. Eis um código digitado sem capricho:

1package main
2import "fmt"
3func main(){
4fmt.Println("Olá, Mundo!")
5    for i:=0;i<3;i++{fmt.Println(i)}
6}

Rodar gofmt baguncado.go (ou go fmt no módulo inteiro) imprime:

1package main
2
3import "fmt"
4
5func main() {
6	fmt.Println("Olá, Mundo!")
7	for i := 0; i < 3; i++ {
8		fmt.Println(i)
9	}
10}

Tabulações para indentar, espaços em volta dos operadores, um comando por linha. Como o código de todo mundo é formatado do mesmo jeito, não há o que discutir nas revisões de código, e todo projeto em Go parece familiar. A maioria dos editores roda o gofmt automaticamente ao salvar.

Lendo dados do teclado

O fmt.Scan lê valores digitados pelo usuário e os guarda em variáveis. Você passa o endereço da variável com & para o Scan poder preenchê-la:

1package main
2
3import "fmt"
4
5func main() {
6	var primeiro, segundo int
7	fmt.Print("Primeiro número: ")
8	fmt.Scan(&primeiro)
9	fmt.Print("Segundo número: ")
10	fmt.Scan(&segundo)
11	fmt.Printf("%d + %d = %d\n", primeiro, segundo, primeiro+segundo)
12}

Uma execução de exemplo, em que os números depois dos dois-pontos são digitados pelo usuário:

Primeiro número: 12
Segundo número: 30
12 + 30 = 42

var primeiro, segundo int declara duas variáveis inteiras. (O próximo artigo da série fala de variáveis a fundo.) Para ler uma linha inteira, com espaços, use um bufio.Reader:

1package main
2
3import (
4	"bufio"
5	"fmt"
6	"os"
7	"strings"
8)
9
10func main() {
11	leitor := bufio.NewReader(os.Stdin)
12	fmt.Print("Qual é o seu nome? ")
13	linha, _ := leitor.ReadString('\n')
14	nome := strings.TrimSpace(linha)
15	fmt.Printf("Olá, %s! Bem-vinda ao Go.\n", nome)
16}
Qual é o seu nome? Ada Lovelace
Olá, Ada Lovelace! Bem-vinda ao Go.

O ReadString('\n') lê até o Enter, inclusive, então o strings.TrimSpace tira o fim de linha (no Windows são dois caracteres, \r\n). O _ ignora o segundo valor que o ReadString devolve, um erro; funções em Go muitas vezes devolvem um resultado e um erro, um padrão que você vai ver em todo lugar.

Códigos de saída

Quando a main de um programa em Go termina, ele sai com o código 0, que quer dizer sucesso. Para informar uma falha, chame o os.Exit com outro número:

1package main
2
3import (
4	"fmt"
5	"os"
6)
7
8func main() {
9	fmt.Println("Algo deu errado!")
10	os.Exit(3)
11}
1$ go build -o falha
2$ ./falha
3Algo deu errado!
4$ echo $?
53

Scripts e ferramentas de build conferem esse número para decidir se continuam. (No PowerShell, use $LASTEXITCODE em vez de $?. E repare que o go run mostra uma saída diferente de zero com uma linha extra, exit status 3.)

Compile para qualquer sistema operacional

Um dos melhores truques do Go: defina duas variáveis de ambiente, GOOS (o sistema operacional de destino) e GOARCH (o processador), e o go build gera um programa para outro sistema, sem ferramenta extra nenhuma. Do mesmo computador com Windows:

1$ GOOS=linux GOARCH=amd64 go build -o ola-linux
2$ GOOS=darwin GOARCH=arm64 go build -o ola-mac
3$ file ola-linux
4ola-linux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, …

O ola-linux roda num servidor Linux de 64 bits, e o ola-mac num Mac com Apple Silicon. (Essa é a sintaxe do Bash; no PowerShell, defina $env:GOOS = "linux" e $env:GOARCH = "amd64" antes.) O go tool dist list mostra todas as combinações suportadas, mais de 40.

Sua vez: pratique

Tente fazer estes antes de espiar as respostas. Coloque cada programa na sua própria pasta com go mod init e rode com go run ..

Exercício 1: Adivinhe a saída (aquecimento). O que exatamente isto imprime?

1package main
2
3import "fmt"
4
5func main() {
6	fmt.Print("Go")
7	fmt.Println("pher", 1, 2)
8	fmt.Printf("%d%%\n", 100)
9	fmt.Println(10/4, 10.0/4)
10}

Exercício 2: Conserte o programa. Ele tem três erros que impedem o build. Ache-os rodando o programa e lendo as mensagens.

1package main
2
3import (
4	"fmt"
5	"strings"
6)
7
8func main()
9{
10	fmt.println("Aprendendo Go")
11}

Exercício 3: Desenhe uma caixa. Escreva um programa que imprima exatamente isto:

+--------+
|  Go!   |
+--------+

Exercício 4: Um recibo. Use o Printf para imprimir uma linha para 3 cafés a 2.5 cada, com o total formatado com 2 casas decimais: 3 x café @ 2.50 = 7.50.

Exercício 5: Conversor de temperatura (desafio). Leia uma temperatura em graus Celsius como número inteiro e imprima em Fahrenheit com uma casa decimal, usando F = C × 9 / 5 + 32. Para 37, deve imprimir 98.6.

Quiz rápido

  1. De qual pacote e de qual função todo programa executável em Go precisa?
  2. Qual é a diferença entre go run e go build?
  3. Por que o Go não compila um programa com um import sem uso?
  4. Por que a { de abertura tem que ficar na mesma linha?
  5. Por que é fmt.Println, e não fmt.println?

Respostas

Exercício 1: O Print não pula linha, então o pher continua na mesma linha, e o Println põe espaços entre os argumentos. O %% imprime um sinal de porcentagem. 10/4 é divisão de inteiros:

1package main
2
3import "fmt"
4
5func main() {
6	fmt.Print("Go")
7	fmt.Println("pher", 1, 2)
8	fmt.Printf("%d%%\n", 100)
9	fmt.Println(10/4, 10.0/4)
10}
Gopher 1 2
100%
2 2.5

Exercício 2: O import strings sem uso, a { sozinha na linha e o println minúsculo. Consertado:

1package main
2
3import "fmt"
4
5func main() {
6	fmt.Println("Aprendendo Go")
7}
Aprendendo Go

(O Go mostra primeiro o erro da chave. É um erro de sintaxe, então o compilador para antes de conferir imports e nomes. Conserte, rode de novo, e os próximos erros aparecem.)

Exercício 3: Um Println por linha:

1package main
2
3import "fmt"
4
5func main() {
6	fmt.Println("+--------+")
7	fmt.Println("|  Go!   |")
8	fmt.Println("+--------+")
9}
+--------+
|  Go!   |
+--------+

Exercício 4: %d para a quantidade, %s para o nome e %.2f para os dois preços:

1package main
2
3import "fmt"
4
5func main() {
6	quantidade := 3
7	preco := 2.5
8	fmt.Printf("%d x %s @ %.2f = %.2f\n", quantidade, "café", preco, float64(quantidade)*preco)
9}
3 x café @ 2.50 = 7.50

float64(quantidade) converte o inteiro num número decimal: o Go nunca mistura int e float64 numa conta automaticamente, mais uma das suas regras rígidas.

Exercício 5: Converta para float64 antes de dividir para as casas decimais sobreviverem:

1package main
2
3import "fmt"
4
5func main() {
6	var celsius int
7	fmt.Print("Temperatura em Celsius: ")
8	fmt.Scan(&celsius)
9	fahrenheit := float64(celsius)*9/5 + 32
10	fmt.Printf("%d C = %.1f F\n", celsius, fahrenheit)
11}
Temperatura em Celsius: 37
37 C = 98.6 F
Temperatura em Celsius: -40
-40 C = -40.0 F

Quiz: (1) Do pacote main e da função main. (2) O go run compila numa pasta temporária e roda o programa na hora; o go build cria um arquivo executável que fica e pode ser copiado para outros computadores. (3) Os criadores do Go fizeram do import sem uso um erro para manter os builds rápidos e o código limpo; apague o import (ou use-o). (4) O Go coloca um ponto e vírgula no fim de uma linha que parece terminada, então uma { na linha seguinte viria depois de um ponto e vírgula, um erro de sintaxe. (5) Nomes que começam com letra maiúscula são exportados pelo pacote; nomes minúsculos são privados dele.

Cola rápida

Eu quero…Escreva
Começar um módulogo mod init ola
Rodar enquanto desenvolvego run .
Gerar um executávelgo build (ou go build -o nome)
O esqueleto de um programapackage main + func main() { … }
Usar um pacoteimport "fmt" (vários: import ( "fmt" "os" ))
Imprimir pulando linhafmt.Println("Oi", nome)
Imprimir um modelofmt.Printf("%s tem %d\n", nome, idade)
Ler um valorfmt.Scan(&idade)
Informar falhaos.Exit(1)
Formatar o códigogofmt -w ola.go ou go fmt ./...
Compilar para LinuxGOOS=linux GOARCH=amd64 go build

Resumindo

Sete linhas, e agora você sabe o que cada uma faz:

  • Um programa executável em Go é package main com uma func main(), dentro de um módulo criado pelo go mod init.
  • go run . compila e roda num passo só; go build gera um executável único e independente (cerca de 1,9 MB para o Olá, Mundo, no nosso build).
  • fmt.Println, Print e Printf cobrem quase toda a impressão.
  • O compilador do Go é rígido: imports e variáveis sem uso são erros, a { fica na mesma linha e as letras maiúsculas decidem o que um pacote exporta.
  • O gofmt formata todo programa em Go do mesmo jeito.
  • Um único comando faz compilação cruzada para Linux, macOS ou Windows.

Próximos passos na série: como instalar o Go no Linux e como definir uma variável em Go. Para ver o quadro geral, leia O Que É a Linguagem de Programação Go?

Obrigado pela leitura!

Conhece alguém que vai gostar? Mande para essa pessoa.

Mais artigos

Leia a seguir

Comentários

Seja gentil e específico. Comentários com links de contas novas aparecem depois da análise de um moderador.