Seu primeiro programa
por Ellery BlackwoodEntenda 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.
- Um programa executável começa com
package maine roda a partir defunc main(). import "fmt"traz o pacote de saída formatada; nomes exportados começam com maiúscula, comofmt.Println.Printlnsepara os valores com espaço e pula linha;Printnão pula;Printfusa verbos e precisa de\n.- Verbos comuns do
Printf:%s,%d,%.2f,%ve%%para o próprio símbolo; larguras como%-10salinham colunas. go run arquivo.gocompila e executa;gofmtformata o código e umimportsem uso é erro de compilação.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Boas-vindas da loja com Println
// 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
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
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.
- O arquivo tem
package main,import "fmt"efunc 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.
package main
import "fmt"
func main() {
fmt.Println("Biblioteca Municipal")
// complete o cartaz
}
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
package mainavisa ao Go que este arquivo é um programa executável, e não uma biblioteca.import "fmt"traz o pacote da biblioteca padrão que sabe imprimir texto no terminal.func main()é o ponto de entrada: o Go roda o que estiver dentro dela, de cima para baixo.- As duas primeiras chamadas de
fmt.Printlnimprimem um texto cada e pulam para a linha seguinte. - Em
fmt.Println("Livros por empréstimo:", 3)o número vai como um segundo valor; oPrintlncoloca um espaço entre os dois. 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(...)compminúsculo: o compilador acusaundefined: 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 do3, porque oPrintlnjá 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.
- Os dados da receita ficam em constantes com nomes claros.
- Toda a ficha é impressa com
fmt.Printf, usando%s,%de%.1fonde couber. - O custo por porção é calculado no código e mostrado com
%.2f. - A saída é idêntica à esperada, linha por linha.
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
}
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
- As constantes
receita,porcoes,farinha,tempoecustoTotaldão nome a cada dado, para oPrintfnão ficar cheio de números soltos. %srecebe o texto da receita e\npula a linha, porque oPrintf, ao contrário doPrintln, não pula sozinho.%dimprime inteiros, como as porções e o tempo de forno.%.1fimprime a farinha com uma casa decimal, saindo2.5.- Na linha do forno, dois verbos
%drecebem dois valores, na mesma ordem em que aparecem. custoTotal/porcoesé calculado na hora e%.2fmostra 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). Ogo vetavisa desse erro; use%dpara inteiros. - Usar
const custoTotal = 26: aícustoTotal/porcoesvira divisão inteira, dá3, e o%.2fmostra%!f(int=03)no lugar do valor. Escreva26.0para 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.
- As linhas separadoras são feitas com
strings.Repeat, com 20 caracteres. - Nomes ficam à esquerda e pontos à direita, usando larguras no
Printf(%-10se%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
%%.
package main
import (
"fmt"
"strings"
)
func main() {
const ana, bruno, carla = 1250, 980, 1430
fmt.Println(strings.Repeat("=", 20))
// complete o placar
}
====================
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
- O
importentre parênteses traz dois pacotes:fmtpara imprimir estringspara montar a linha separadora. const ana, bruno, carla = 1250, 980, 1430declara as três pontuações numa linha só; os valores são fixos, então constante é o mais claro.total := ana + bruno + carlasoma no programa, para o total nunca ficar diferente das parcelas.float64(carla) / float64(total) * 100converte para decimal antes de dividir; sem isso,1430 / 3660seria divisão inteira e daria0.strings.Repeat("=", 20)devolve um texto com 20 sinais de igual, do mesmo tamanho das linhas da tabela.%-10s%10dreserva 10 colunas para o nome (alinhado à esquerda) e 10 para o número (alinhado à direita), formando colunas retas.- Na última linha,
%.1fmostra 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ó: oPrintflê% dcomo um novo verbo, sem valor para ele, e a saída mostra39.1%!d(MISSING)os pontos. O certo é%%. - Calcular
carla / total * 100: com inteiros,1430 / 3660dá0, e o percentual sai0. Converta parafloat64antes da divisão. - Calcular
float64(carla / total) * 100: a conversão vem tarde demais, depois da divisão inteira, e o resultado continua0.0. - Usar
%10spara 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)