Programação em Go do Zero com 25 Exemplos
Go (Golang) é uma linguagem criada no Google. É simples, compila rapidamente e tem concorrência embutida, por isso é popular em servidores, ferramentas e sistemas de nuvem. Este artigo tem 25 exemplos de código, cada um executado com Go 1.27, e a saída real de cada um. Os exemplos vão do básico à concorrência, passando por handlers web e generics.
O que você precisa
Instale o Go em go.dev/dl e verifique com `go version`. Crie um arquivo `.go` e execute com `go run nomedoarquivo.go`.
Ilustração
Exemplo 1: Olá, mundo
O programa Go mais simples. Todo programa começa com o pacote main e a função main.
package main
import "fmt"
func main() {
fmt.Println("Olá, Go")
}
Saída real
Olá, Go
Exemplo 2: Variáveis e constantes
`:=` declara e atribui valor em um único passo, `var` declara de forma explícita, e `const` é usado para valores que nunca mudam.
package main
import "fmt"
const schoolName = "Escola Exemplo"
func main() {
name := "Budi"
var age int = 20
fmt.Println(schoolName, name, age)
}
Saída real
Escola Exemplo Budi 20
Exemplo 3: Valores zero
Uma variável declarada sem valor recebe o valor zero do seu tipo, como 0, string vazia ou false.
package main
import "fmt"
func main() {
var n int
var s string
var b bool
var f float64
fmt.Printf("int=%d string=%q bool=%t float=%.1f\n", n, s, b, f)
}
Saída real
int=0 string="" bool=false float=0.0
Exemplo 4: if e else
Tomada de decisão com if e else if. Go não exige parênteses em volta da condição.
package main
import "fmt"
func main() {
score := 72
if score >= 80 {
fmt.Println("A")
} else if score >= 70 {
fmt.Println("B")
} else {
fmt.Println("C")
}
}
Saída real
B
Exemplo 5: Laço for
Go tem apenas uma palavra-chave de repetição, o for, que pode contar ou funcionar como um while.
package main
import "fmt"
func main() {
for i := 1; i <= 3; i++ {
fmt.Println("contagem", i)
}
n := 0
for n < 2 {
n++
}
fmt.Println("n =", n)
}
Saída real
contagem 1
contagem 2
contagem 3
n = 2
Exemplo 6: switch
O switch compara vários casos e não passa para o próximo caso a menos que você peça.
package main
import "fmt"
func main() {
day := "Sábado"
switch day {
case "Sábado", "Domingo":
fmt.Println("dia de folga")
default:
fmt.Println("dia útil")
}
}
Saída real
dia de folga
Exemplo 7: Arrays e slices
Arrays têm tamanho fixo. Slices crescem com append e podem ser fatiados com s[a:b].
package main
import "fmt"
func main() {
arr := [3]int{1, 2, 3}
s := []int{10, 20}
s = append(s, 30, 40)
fmt.Println("array:", arr, "len:", len(arr))
fmt.Println("slice:", s, "len:", len(s), "cap:", cap(s) >= 4)
fmt.Println("fatia:", s[1:3])
}
Saída real
array: [1 2 3] len: 3
slice: [10 20 30 40] len: 4 cap: true
fatia: [20 30]
Exemplo 8: Map
Um map guarda pares chave-valor. A forma `v, ok :=` verifica se uma chave existe.
package main
import "fmt"
func main() {
scores := map[string]int{"Budi": 85, "Siti": 72}
scores["Andi"] = 45
if v, ok := scores["Budi"]; ok {
fmt.Println("nota:", v)
}
delete(scores, "Siti")
fmt.Println("quantidade:", len(scores))
}
Saída real
nota: 85
quantidade: 2
Exemplo 9: Função com vários retornos
Uma função pode devolver vários valores. Erros geralmente são devolvidos como último valor.
package main
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("não é possível dividir por zero")
}
return a / b, nil
}
func main() {
q, err := divide(10, 2)
fmt.Println("resultado:", q, "erro:", err)
_, err = divide(1, 0)
fmt.Println("erro:", err)
}
Saída real
resultado: 5 erro: <nil>
erro: não é possível dividir por zero
Exemplo 10: Closure
Uma função que lembra variáveis do escopo em que foi criada. Útil para contadores e estado privado.
package main
import "fmt"
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
next := counter()
fmt.Println(next(), next(), next())
}
Saída real
1 2 3
Exemplo 11: Struct e método
Uma struct agrupa dados, e um método dá comportamento a esse tipo.
package main
import "fmt"
type Student struct {
Name string
Score int
}
func (s Student) Grade() string {
if s.Score >= 80 {
return "A"
}
return "B"
}
func main() {
s := Student{Name: "Budi", Score: 85}
fmt.Println(s.Name, s.Grade())
}
Saída real
Budi A
Exemplo 12: Interface
Uma interface lista os métodos que um tipo precisa ter. Qualquer tipo que tenha esses métodos satisfaz a interface automaticamente.
package main
import "fmt"
type Shape interface {
Area() float64
}
type Rect struct{ W, H float64 }
func (r Rect) Area() float64 { return r.W * r.H }
func main() {
var s Shape = Rect{W: 3, H: 4}
fmt.Printf("área = %.1f\n", s.Area())
}
Saída real
área = 12.0
Exemplo 13: Ponteiros
&x fornece o endereço de uma variável, e *p lê ou altera o valor nesse endereço, então uma função pode alterar os dados de quem a chamou.
package main
import "fmt"
func increment(n *int) {
*n++
}
func main() {
x := 5
increment(&x)
fmt.Println("x =", x)
}
Saída real
x = 6
Exemplo 14: Tratando erros
Crie um erro com fmt.Errorf e %w, depois verifique com errors.Is se ele corresponde a um erro conhecido.
package main
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("dado não encontrado")
func find(id int) error {
if id != 1 {
return fmt.Errorf("código %d: %w", id, ErrNotFound)
}
return nil
}
func main() {
err := find(2)
fmt.Println(err)
fmt.Println("corresponde a ErrNotFound:", errors.Is(err, ErrNotFound))
}
Saída real
código 2: dado não encontrado
corresponde a ErrNotFound: true
Exemplo 15: defer
defer adia uma chamada até a função que a contém terminar. É ideal para fechar arquivos e liberar recursos.
package main
import "fmt"
func main() {
defer fmt.Println("executado por último")
fmt.Println("início")
fmt.Println("processando")
}
Saída real
início
processando
executado por último
Exemplo 16: panic e recover
panic interrompe a execução normal, e recover só pode capturá-lo dentro de uma função que usa defer, para que o programa não trave.
package main
import "fmt"
func safeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recuperado de panic: %v", r)
}
}()
return a / b, nil
}
func main() {
fmt.Println(safeDivide(10, 2))
fmt.Println(safeDivide(1, 0))
}
Saída real
5 <nil>
0 recuperado de panic: runtime error: integer divide by zero
Exemplo 17: Goroutine
A palavra-chave go inicia trabalho que roda de forma concorrente. sync.WaitGroup espera até que todo o trabalho termine.
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
_ = n * n
}(i)
}
wg.Wait()
fmt.Println("todas as tarefas concluídas")
}
Saída real
todas as tarefas concluídas
Exemplo 18: Channel
Channels enviam valores entre goroutines. Este exemplo envia valores de uma goroutine para main e depois fecha o channel.
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
for i := 1; i <= 3; i++ {
ch <- i * 10
}
close(ch)
}()
for v := range ch {
fmt.Println("recebeu", v)
}
}
Saída real
recebeu 10
recebeu 20
recebeu 30
Exemplo 19: select e timeout
select espera vários channels ao mesmo tempo. time.After define um tempo máximo de espera.
package main
import (
"fmt"
"time"
)
func main() {
result := make(chan string)
go func() {
time.Sleep(200 * time.Millisecond)
result <- "concluído"
}()
select {
case msg := <-result:
fmt.Println(msg)
case <-time.After(50 * time.Millisecond):
fmt.Println("tempo esgotado")
}
}
Saída real
tempo esgotado
Exemplo 20: Mutex para dados compartilhados
sync.Mutex permite que muitas goroutines alterem uma mesma variável com segurança. O total está sempre correto.
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
var wg sync.WaitGroup
total := 0
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
total++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("total =", total)
}
Saída real
total = 100
Exemplo 21: Pacotes strings e rune
strings oferece funções de texto. len conta bytes, então conte caracteres não ASCII convertendo para []rune.
package main
import (
"fmt"
"strings"
)
func main() {
s := "Go é fácil de aprender"
fmt.Println(strings.ToUpper("go"), strings.Contains(s, "fácil"))
fmt.Println(strings.Split("a,b,c", ","), len("café"), len([]rune("café")))
fmt.Println([]rune("café")[3] == 'é')
}
Saída real
GO true
[a b c] 5 4
true
Exemplo 22: Lendo e gravando arquivos
os.WriteFile e os.ReadFile gravam e leem o arquivo inteiro em uma única chamada.
package main
import (
"fmt"
"os"
)
func main() {
if err := os.WriteFile("nota.txt", []byte("anotação do Go\n"), 0644); err != nil {
fmt.Println("falha ao gravar:", err)
return
}
data, err := os.ReadFile("nota.txt")
if err != nil {
fmt.Println("falha ao ler:", err)
return
}
fmt.Print("lido: ", string(data))
}
Saída real
lido: anotação do Go
Exemplo 23: JSON
encoding/json converte uma struct em JSON e vice-versa. Tags como `json:"..."` definem o nome dos campos.
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
Name string `json:"name"`
Score int `json:"score"`
}
func main() {
b, _ := json.Marshal(Student{Name: "Budi", Score: 85})
fmt.Println(string(b))
var s Student
_ = json.Unmarshal([]byte(`{"name":"Siti","score":72}`), &s)
fmt.Println(s.Name, s.Score)
}
Saída real
{"name":"Budi","score":85}
Siti 72
Exemplo 24: Testando um handler HTTP
httptest testa uma função handler sem executar um servidor de verdade.
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Olá do Go HTTP")
}
func main() {
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
hello(rec, req)
body, _ := io.ReadAll(rec.Result().Body)
fmt.Println(rec.Code, string(body))
}
Saída real
200 Olá do Go HTTP
Exemplo 25: Generics
Funções que trabalham com vários tipos usando um parâmetro de tipo T, restrito por uma interface.
package main
import "fmt"
type Number interface {
~int | ~float64
}
func Sum[T Number](values []T) T {
var total T
for _, v := range values {
total += v
}
return total
}
func main() {
fmt.Println(Sum([]int{1, 2, 3}))
fmt.Println(Sum([]float64{1.5, 2.5}))
}
Saída real
6
4
Próximos passos
Tente escrever um servidor web que recebe JSON e o salva em um arquivo. Depois, estude o pacote net/http e o context, para timeouts e cancelamento.
Resumo
Go tem uma sintaxe simples, verifica tipos na compilação, trata erros como valores e oferece concorrência com goroutines e channels, o que o torna adequado para servidores e cargas de trabalho com muitas tarefas simultâneas.