Sua dose diária de programação

Conceito, 3 exemplos e 3 exercícios: uma pequena conquista de cada vez.

✦   Lição

Seu primeiro programa

Todo programa Go executável segue a mesma estrutura: a linha package main diz que o arquivo é um programa (e não uma biblioteca), os import trazem os pacotes que ele usa e a função func main() é o ponto de partida. Quando você roda go run main.go, o Go compila o arquivo e executa o que está dentro de main, de cima para baixo.

Go Fundamentos Iniciante 3 exemplos + 3 exercícios
42 lições publicadas 10 linguagens novas lições todo dia útil
Go / Fundamentos

Seu primeiro programa

por Ellery Blackwood
Iniciante

Entenda o conceito

Todo programa Go executável segue a mesma estrutura: a linha package main diz que o arquivo é um programa (e não uma biblioteca), os import trazem os pacotes que ele usa e a função func main() é o ponto de partida. Quando você roda go run main.go, o Go compila o arquivo e executa o que está dentro de main, de cima para baixo.

Para mostrar texto no terminal, usamos o pacote fmt da biblioteca padrão. fmt.Println imprime os valores separados por espaço e pula a linha no fim; fmt.Print imprime sem pular linha; fmt.Printf recebe um texto de formato com verbos, como %s (texto), %d (inteiro), %.2f (decimal com 2 casas) e %v (qualquer valor).

O Go é rigoroso desde o primeiro programa: um import que não é usado impede a compilação, e o código tem um formato oficial, aplicado pelo gofmt (tabulação para indentar, chave { na mesma linha da função). Isso parece chato no começo, mas deixa qualquer código Go com a mesma cara.

↳ Pontos-chave
  • Um programa executável começa com package main e roda a partir de func main().
  • import "fmt" traz o pacote de saída formatada; nomes exportados começam com maiúscula, como fmt.Println.
  • Println separa os valores com espaço e pula linha; Print não pula; Printf usa verbos e precisa de \n.
  • Verbos comuns do Printf: %s, %d, %.2f, %v e %% para o próprio símbolo; larguras como %-10s alinham colunas.
  • go run arquivo.go compila e executa; gofmt formata o código e um import sem uso é erro de compilação.

Do conceito à prática

3 exemplos para ver a ideia funcionando.

01Boas-vindas da loja com Println

ola.go
// Todo arquivo Go começa dizendo a qual pacote pertence.
// O pacote main é o de um programa executável.
package main

// fmt é o pacote da biblioteca padrão para imprimir e formatar texto.
import "fmt"

// A execução começa sempre pela função main.
func main() {
	fmt.Println("Olá! Bem-vindo à Loja do Bairro.")

	// Println aceita vários valores e coloca um espaço entre eles.
	fmt.Println("Hoje temos", 3, "promoções.")

	// Uma linha vazia ajuda a separar blocos na saída.
	fmt.Println()

	fmt.Println("Promoções do dia:")
	fmt.Println("- Café 500 g")
	fmt.Println("- Pão de forma")
	fmt.Println("- Leite integral")
}

Este é o esqueleto de qualquer programa Go: package main, o import do fmt e a função main. Cada fmt.Println gera uma linha, e a ordem das chamadas é a ordem da saída.

Repare que fmt.Println("Hoje temos", 3, "promoções.") mistura texto e número sem conversão nenhuma: o Println imprime cada valor e coloca um espaço entre eles. Chamado sem argumentos, ele imprime só a quebra de linha.

02Cupom do carrinho com Print, Println e Printf

cupom.go
package main

import "fmt"

func main() {
	// Constantes guardam valores fixos com nome claro.
	const loja = "Loja do Bairro"
	const itens = 4
	const total = 57.9

	// Print não pula linha sozinho: o \n faz isso.
	fmt.Print("Cupom fiscal - ")
	fmt.Print(loja, "\n")

	// Println pula linha no fim e separa os valores com espaço.
	fmt.Println("Itens no carrinho:", itens)

	// Printf usa verbos: %s texto, %d inteiro, %.2f decimal com 2 casas.
	fmt.Printf("Loja: %s\n", loja)
	fmt.Printf("Quantidade: %d itens\n", itens)
	fmt.Printf("Total: R$ %.2f\n", total)

	// %v imprime qualquer valor no formato padrão.
	fmt.Printf("Resumo: %v itens, R$ %v\n", itens, total)
}

Aqui as três funções de saída aparecem lado a lado. fmt.Print não pula linha, por isso o \n vai no fim; fmt.Println pula sozinho; fmt.Printf encaixa cada valor no verbo correspondente, na ordem.

A última linha mostra a diferença entre %.2f e %v: o primeiro força duas casas (57.90), o segundo usa o formato padrão do valor (57.9). Para dinheiro, prefira sempre o formato com casas fixas.

03Boletim alinhado em colunas

boletim.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	const aluna = "Marina Costa"
	const turma = "7º B"

	// strings.Repeat monta uma linha separadora sem digitar 30 traços.
	linha := strings.Repeat("-", 30)

	fmt.Println(linha)
	fmt.Printf("Boletim de %s (%s)\n", aluna, turma)
	fmt.Println(linha)

	// %-12s alinha o texto à esquerda em 12 colunas;
	// %6.1f alinha o número à direita em 6 colunas, com 1 casa.
	fmt.Printf("%-12s%6s\n", "Disciplina", "Nota")
	fmt.Printf("%-12s%6.1f\n", "Matemática", 8.5)
	fmt.Printf("%-12s%6.1f\n", "Português", 9.0)
	fmt.Printf("%-12s%6.1f\n", "Ciências", 7.5)

	media := (8.5 + 9.0 + 7.5) / 3
	fmt.Println(linha)
	fmt.Printf("%-12s%6.2f\n", "Média", media)

	// %q mostra o texto entre aspas, útil para conferir espaços.
	fmt.Printf("Situação: %q\n", "aprovada")
}

Um programa um pouco mais completo: importa dois pacotes entre parênteses, usa strings.Repeat para a linha separadora e calcula a média no próprio código. As larguras nos verbos (%-12s e %6.1f) completam com espaços, e as colunas ficam alinhadas.

A largura conta caracteres, e não bytes, por isso Matemática e Português, com acento, ficam alinhadas como as outras. O %q imprime o texto entre aspas, um jeito rápido de conferir se sobrou algum espaço.


Agora é com você

Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.

01Cartaz da bibliotecaFácil

Escreva um programa que imprima o cartaz de avisos da biblioteca municipal, uma informação por linha, exatamente como na saída esperada.

↳ Requisitos
  • O arquivo tem package main, import "fmt" e func main().
  • Cada linha do cartaz é impressa com uma chamada de fmt.Println.
  • O número 3 é passado como valor separado do texto, e não dentro das aspas.
  • A linha em branco é feita com fmt.Println() sem argumentos.
código inicial
package main

import "fmt"

func main() {
	fmt.Println("Biblioteca Municipal")
	// complete o cartaz
}
saída esperada
Biblioteca Municipal
Horário: 8h às 18h
Livros por empréstimo: 3

Boa leitura!
Ver dica

O Println já coloca um espaço entre os valores que recebe; não deixe espaço sobrando no fim do texto antes do número.

Ver resposta
package main

import "fmt"

func main() {
	// Uma chamada de Println para cada linha do cartaz.
	fmt.Println("Biblioteca Municipal")
	fmt.Println("Horário: 8h às 18h")

	// O número vai como valor separado; Println põe o espaço.
	fmt.Println("Livros por empréstimo:", 3)

	// Println sem argumentos imprime só a quebra de linha.
	fmt.Println()
	fmt.Println("Boa leitura!")
}

Passo a passo

  1. package main avisa ao Go que este arquivo é um programa executável, e não uma biblioteca.
  2. import "fmt" traz o pacote da biblioteca padrão que sabe imprimir texto no terminal.
  3. func main() é o ponto de entrada: o Go roda o que estiver dentro dela, de cima para baixo.
  4. As duas primeiras chamadas de fmt.Println imprimem um texto cada e pulam para a linha seguinte.
  5. Em fmt.Println("Livros por empréstimo:", 3) o número vai como um segundo valor; o Println coloca um espaço entre os dois.
  6. fmt.Println() sem nada dentro imprime só a quebra de linha, criando a linha vazia do cartaz.

Por que funciona

Cada fmt.Println escreve seus valores e termina com \n, então cinco chamadas geram exatamente cinco linhas, na ordem em que aparecem no código. Como a função main roda de cima para baixo, a ordem do código é a ordem da saída.

Passar o 3 como valor separado mostra que o Println aceita textos e números juntos, cuidando sozinho do espaço entre eles.

Erros comuns

  • Escrever fmt.println(...) com p minúsculo: o compilador acusa undefined: fmt.println. Em Go, só nomes com inicial maiúscula são exportados por um pacote; o certo é fmt.Println.
  • Usar aspas simples, como fmt.Println('Boa leitura!'): aspas simples são para um único caractere (rune) e o código não compila. Texto usa aspas duplas.
  • Escrever fmt.Println("Livros por empréstimo: ", 3), com espaço no fim do texto: a saída ganha dois espaços antes do 3, porque o Println já põe um.
  • Esquecer o fmt.Println() vazio: o programa roda, mas a saída fica sem a linha em branco e não bate com a esperada.

Outra forma de resolver

Dá para usar uma só chamada com o texto em várias linhas, usando crase (string literal crua):

fmt.Print(`Biblioteca Municipal
Horário: 8h às 18h
Livros por empréstimo: 3

Boa leitura!
`)

Essa forma é boa para blocos fixos de texto, como menus e cartazes. Separar em várias chamadas é melhor quando cada linha vai ganhar valores calculados.

Saída esperada

Biblioteca Municipal
Horário: 8h às 18h
Livros por empréstimo: 3

Boa leitura!

02Ficha de receita com PrintfMédio

Monte a ficha de um bolo de cenoura usando fmt.Printf. O custo por porção deve ser calculado no programa, dividindo o custo total (R$ 26,00) pelas 8 porções.

↳ Requisitos
  • Os dados da receita ficam em constantes com nomes claros.
  • Toda a ficha é impressa com fmt.Printf, usando %s, %d e %.1f onde couber.
  • O custo por porção é calculado no código e mostrado com %.2f.
  • A saída é idêntica à esperada, linha por linha.
código inicial
package main

import "fmt"

func main() {
	const receita = "Bolo de cenoura"
	const porcoes = 8
	const farinha = 2.5
	const tempo = 40
	const custoTotal = 26.0

	fmt.Printf("Receita: %s\n", receita)
	// imprima o resto da ficha com fmt.Printf
}
saída esperada
Receita: Bolo de cenoura
Rende: 8 porções
Farinha: 2.5 xícaras
Forno: 40 minutos a 180 °C
Custo por porção: R$ 3.25
Ver dica

O Printf não pula linha sozinho: termine cada formato com \n. E escolha o verbo pelo tipo do valor.

Ver resposta
package main

import "fmt"

func main() {
	// Dados fixos da receita, com nomes claros.
	const receita = "Bolo de cenoura"
	const porcoes = 8
	const farinha = 2.5
	const tempo = 40
	const custoTotal = 26.0

	// Cada verbo do Printf recebe um valor, na ordem.
	fmt.Printf("Receita: %s\n", receita)
	fmt.Printf("Rende: %d porções\n", porcoes)
	fmt.Printf("Farinha: %.1f xícaras\n", farinha)
	fmt.Printf("Forno: %d minutos a %d °C\n", tempo, 180)

	// A conta é feita no programa, não à mão.
	fmt.Printf("Custo por porção: R$ %.2f\n", custoTotal/porcoes)
}

Passo a passo

  1. As constantes receita, porcoes, farinha, tempo e custoTotal dão nome a cada dado, para o Printf não ficar cheio de números soltos.
  2. %s recebe o texto da receita e \n pula a linha, porque o Printf, ao contrário do Println, não pula sozinho.
  3. %d imprime inteiros, como as porções e o tempo de forno.
  4. %.1f imprime a farinha com uma casa decimal, saindo 2.5.
  5. Na linha do forno, dois verbos %d recebem dois valores, na mesma ordem em que aparecem.
  6. custoTotal/porcoes é calculado na hora e %.2f mostra o resultado com duas casas, como se espera de um valor em reais.

Por que funciona

O Printf lê o texto de formato da esquerda para a direita e, a cada verbo (%s, %d, %.1f, %.2f), consome o próximo argumento da lista. Assim o texto fixo e os valores ficam separados: dá para mudar a receita trocando só as constantes.

As constantes sem tipo explícito se adaptam ao uso: custoTotal é 26.0, então custoTotal/porcoes vira uma divisão decimal e dá 3.25, e não uma divisão inteira.

Erros comuns

  • Esquecer o \n: fmt.Printf("Receita: %s", receita) faz a próxima linha grudar nesta, e a saída vira uma linha só.
  • Trocar o verbo, como fmt.Printf("Rende: %s porções\n", porcoes): o programa compila, mas imprime %!s(int=8). O go vet avisa desse erro; use %d para inteiros.
  • Usar const custoTotal = 26: aí custoTotal/porcoes vira divisão inteira, dá 3, e o %.2f mostra %!f(int=03) no lugar do valor. Escreva 26.0 para a conta ser decimal.
  • Passar menos valores que verbos, como fmt.Printf("Forno: %d minutos a %d °C\n", tempo): a saída mostra %!d(MISSING) no lugar do segundo número.

Outra forma de resolver

Com fmt.Println também funciona, mas sem controle das casas decimais:

fmt.Println("Farinha:", farinha, "xícaras")
fmt.Println("Custo por porção: R$", custoTotal/porcoes)

Prefira o Println para mensagens rápidas e o Printf quando o formato importa, como dinheiro com duas casas.

Saída esperada

Receita: Bolo de cenoura
Rende: 8 porções
Farinha: 2.5 xícaras
Forno: 40 minutos a 180 °C
Custo por porção: R$ 3.25

03Placar do campeonato em tabelaDesafio

Imprima o placar da rodada 5 de um jogo como uma tabela de 20 colunas: Ana fez 1250 pontos, Bruno 980 e Carla 1430. No fim, mostre o total e o percentual dos pontos da líder com uma casa decimal.

↳ Requisitos
  • As linhas separadoras são feitas com strings.Repeat, com 20 caracteres.
  • Nomes ficam à esquerda e pontos à direita, usando larguras no Printf (%-10s e %10d).
  • O total e o percentual são calculados no código, sem divisão inteira.
  • O símbolo de porcentagem aparece na saída usando %%.
código inicial
package main

import (
	"fmt"
	"strings"
)

func main() {
	const ana, bruno, carla = 1250, 980, 1430

	fmt.Println(strings.Repeat("=", 20))
	// complete o placar
}
saída esperada
====================
PLACAR - RODADA 5
====================
Jogador       Pontos
Ana             1250
Bruno            980
Carla           1430
--------------------
Total           3660
Líder: Carla (39.1% dos pontos)
Ver dica

Some e divida no programa, mas converta os inteiros para float64 antes da divisão; e lembre que o % sozinho começa um verbo.

Ver resposta
package main

import (
	"fmt"
	"strings"
)

func main() {
	const ana, bruno, carla = 1250, 980, 1430

	total := ana + bruno + carla
	// Converte para float64 antes de dividir, senão a divisão é inteira.
	percentual := float64(carla) / float64(total) * 100

	fmt.Println(strings.Repeat("=", 20))
	fmt.Println("PLACAR - RODADA 5")
	fmt.Println(strings.Repeat("=", 20))

	// %-10s: texto à esquerda em 10 colunas; %10d: número à direita.
	fmt.Printf("%-10s%10s\n", "Jogador", "Pontos")
	fmt.Printf("%-10s%10d\n", "Ana", ana)
	fmt.Printf("%-10s%10d\n", "Bruno", bruno)
	fmt.Printf("%-10s%10d\n", "Carla", carla)

	fmt.Println(strings.Repeat("-", 20))
	fmt.Printf("%-10s%10d\n", "Total", total)

	// %% imprime o próprio símbolo de porcentagem.
	fmt.Printf("Líder: %s (%.1f%% dos pontos)\n", "Carla", percentual)
}

Passo a passo

  1. O import entre parênteses traz dois pacotes: fmt para imprimir e strings para montar a linha separadora.
  2. const ana, bruno, carla = 1250, 980, 1430 declara as três pontuações numa linha só; os valores são fixos, então constante é o mais claro.
  3. total := ana + bruno + carla soma no programa, para o total nunca ficar diferente das parcelas.
  4. float64(carla) / float64(total) * 100 converte para decimal antes de dividir; sem isso, 1430 / 3660 seria divisão inteira e daria 0.
  5. strings.Repeat("=", 20) devolve um texto com 20 sinais de igual, do mesmo tamanho das linhas da tabela.
  6. %-10s%10d reserva 10 colunas para o nome (alinhado à esquerda) e 10 para o número (alinhado à direita), formando colunas retas.
  7. Na última linha, %.1f mostra o percentual com uma casa e %% imprime o símbolo %.

Por que funciona

A largura nos verbos (%-10s, %10d, %10s) faz o Printf completar com espaços até o tamanho pedido. Como todas as linhas da tabela usam as mesmas larguras, cada uma tem 20 caracteres e as colunas se alinham, seja qual for o tamanho do nome ou do número. O sinal de menos muda o alinhamento para a esquerda, o que costuma ser o certo para texto; números ficam melhores à direita.

O % é o caractere especial do Printf, por isso precisa ser dobrado para aparecer na saída. E a conversão para float64 é necessária porque, em Go, a divisão entre inteiros descarta a parte decimal.

Erros comuns

  • Escrever (%.1f% dos pontos) com um % só: o Printf lê % d como um novo verbo, sem valor para ele, e a saída mostra 39.1%!d(MISSING)os pontos. O certo é %%.
  • Calcular carla / total * 100: com inteiros, 1430 / 3660 dá 0, e o percentual sai 0. Converta para float64 antes da divisão.
  • Calcular float64(carla / total) * 100: a conversão vem tarde demais, depois da divisão inteira, e o resultado continua 0.0.
  • Usar %10s para o nome: os nomes ficam encostados à direita da coluna e a saída não bate com a esperada. Use %-10s.
  • Digitar o total à mão (fmt.Printf("%-10s%10d\n", "Total", 3660)): funciona hoje, mas fica errado na primeira mudança de pontuação.

Outra forma de resolver

Com o pacote text/tabwriter da biblioteca padrão, as colunas se ajustam ao maior valor sem você escolher larguras (importe os e text/tabwriter):

w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', tabwriter.AlignRight)
fmt.Fprintln(w, "Jogador\tPontos\t")
fmt.Fprintln(w, "Ana\t1250\t")
w.Flush()

Com tabwriter.AlignRight todas as colunas ficam à direita. Ela é preferível quando os nomes têm tamanhos imprevisíveis. Para uma tabela pequena e de tamanho conhecido, larguras fixas no Printf são mais simples e dão uma saída exata.

Saída esperada

====================
PLACAR - RODADA 5
====================
Jogador       Pontos
Ana             1250
Bruno            980
Carla           1430
--------------------
Total           3660
Líder: Carla (39.1% dos pontos)

Últimas lições

Ver o arquivo completo →