Menu
Coddy logo textTech

Erros Sentinela

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 55 de 107.

Um erro sentinela é uma variável de erro predefinida em nível de pacote que representa uma condição de erro específica. Ao contrário de criar novos erros a cada vez com errors.New, os erros sentinela são declarados uma única vez e reutilizados em todo o seu código.

Você define erros sentinela como variáveis de nível de pacote, geralmente com nomes começando com Err:

package user

import "errors"

var (
    ErrNotFound     = errors.New("user not found")
    ErrInvalidEmail = errors.New("invalid email address")
    ErrDuplicate    = errors.New("user already exists")
)

As funções retornam estes erros predefinidos quando condições específicas ocorrem:

func FindUser(id int) (*User, error) {
    user, exists := users[id]
    if !exists {
        return nil, ErrNotFound
    }
    return user, nil
}

O poder dos erros sentinela é que os chamadores podem verificar condições de erro específicas comparando os valores de erro diretamente:

user, err := FindUser(42)
if err == ErrNotFound {
    fmt.Println("Creating new user...")
} else if err != nil {
    fmt.Println("Unexpected error:", err)
}

A biblioteca padrão do Go usa erros sentinela extensivamente. Por exemplo, io.EOF sinaliza o fim da entrada, e sql.ErrNoRows indica um resultado de consulta vazio. Este padrão cria um contrato claro entre os pacotes e seus usuários sobre quais erros esperar.

No entanto, verificações de igualdade simples falham quando os erros são envolvidos. Na próxima lição, você aprenderá como errors.Is() resolve esse problema verificando toda a cadeia de erros.

challenge icon

Desafio

Fácil

Vamos construir um sistema de gerenciamento de inventário que utiliza erros sentinela para comunicar condições de falha específicas. Você definirá variáveis de erro no nível do pacote que os chamadores podem verificar para lidar com diferentes cenários adequadamente.

Você organizará seu código em dois arquivos:

  • inventory.go: Crie um sistema de inventário com erros sentinela predefinidos para casos de falha comuns.

    Defina três erros sentinela no nível do pacote:

    • ErrItemNotFound com a mensagem "item not found in inventory"
    • ErrOutOfStock com a mensagem "item is out of stock"
    • ErrInsufficientQuantity com a mensagem "insufficient quantity available"

    Crie uma struct Inventory que contém um mapa de nomes de itens para suas quantidades. Implemente estes métodos:

    • NewInventory() *Inventory - cria um inventário vazio
    • AddItem(name string, quantity int) - adiciona ou atualiza a quantidade de um item
    • GetQuantity(name string) (int, error) - retorna a quantidade de um item, ou ErrItemNotFound se ele não existir
    • Purchase(name string, quantity int) error - tenta comprar itens. Retorne ErrItemNotFound se o item não existir, ErrOutOfStock se a quantidade atual for zero, ou ErrInsufficientQuantity se a quantidade solicitada exceder o estoque disponível. Em caso de sucesso, reduza o inventário e retorne nil.
  • main.go: Leia as operações de inventário da entrada e demonstre como os chamadores podem verificar erros sentinela específicos usando comparação direta de igualdade.

    Leia o nome do item e a quantidade de compra da entrada. Crie um inventário, adicione o item "laptop" com a quantidade 5, e então tente a compra. Com base no erro retornado, imprima uma mensagem específica mostrando que você identificou qual erro sentinela ocorreu.

As seguintes entradas serão fornecidas:

  • Linha 1: Nome do item para comprar
  • Linha 2: Quantidade para comprar

Trate o resultado verificando qual erro específico foi retornado:

  • Se err == ErrItemNotFound: imprima Error: Item '[name]' does not exist in our inventory
  • Se err == ErrOutOfStock: imprima Error: Item '[name]' is currently out of stock
  • Se err == ErrInsufficientQuantity: imprima Error: Cannot purchase [quantity] units of '[name]' - not enough in stock
  • Se for bem-sucedido: imprima Successfully purchased [quantity] units of '[name]'

Por exemplo, dados laptop e 3, sua saída deve ser:

Successfully purchased 3 units of 'laptop'

E dados phone e 2, sua saída deve ser:

Error: Item 'phone' does not exist in our inventory

E dados laptop e 10, sua saída deve ser:

Error: Cannot purchase 10 units of 'laptop' - not enough in stock

Folha de consulta

Um erro sentinela é uma variável de erro predefinida em nível de pacote que representa uma condição de erro específica. Erros sentinela são declarados uma vez e reutilizados em todo o seu código.

Defina erros sentinela como variáveis em nível de pacote, normalmente com nomes começando com Err:

package user

import "errors"

var (
    ErrNotFound     = errors.New("user not found")
    ErrInvalidEmail = errors.New("invalid email address")
    ErrDuplicate    = errors.New("user already exists")
)

As funções retornam esses erros predefinidos quando condições específicas ocorrem:

func FindUser(id int) (*User, error) {
    user, exists := users[id]
    if !exists {
        return nil, ErrNotFound
    }
    return user, nil
}

Quem chama a função pode verificar condições de erro específicas comparando os valores de erro diretamente:

user, err := FindUser(42)
if err == ErrNotFound {
    fmt.Println("Creating new user...")
} else if err != nil {
    fmt.Println("Unexpected error:", err)
}

A biblioteca padrão do Go usa erros sentinela extensivamente, como io.EOF e sql.ErrNoRows.

Experimente você mesmo

package main

import (
	"fmt"
)

func main() {
	// Ler a entrada
	var itemName string
	var quantity int
	fmt.Scanln(&itemName)
	fmt.Scanln(&quantity)

	// Criar inventário e adicionar "laptop" com quantidade 5
	inv := NewInventory()
	inv.AddItem("laptop", 5)

	// TODO: Tentar comprar o item
	// Chamar inv.Purchase(itemName, quantity)

	// TODO: Verificar qual erro sentinela específico foi retornado usando comparação direta de igualdade
	// Usar instruções if/else if para verificar:
	// - err == ErrItemNotFound
	// - err == ErrOutOfStock
	// - err == ErrInsufficientQuantity
	// - err == nil (sucesso)

	// TODO: Imprimir a mensagem apropriada com base no erro
	// Se ErrItemNotFound: fmt.Printf("Error: Item '%s' does not exist in our inventory\n", itemName)
	// Se ErrOutOfStock: fmt.Printf("Error: Item '%s' is currently out of stock\n", itemName)
	// Se ErrInsufficientQuantity: fmt.Printf("Error: Cannot purchase %d units of '%s' - not enough in stock\n", quantity, itemName)
	// Se sucesso: fmt.Printf("Successfully purchased %d units of '%s'\n", quantity, itemName)
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos