Menu
Coddy logo textTech

Errores centinela

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 55 de 107.

Un error centinela es una variable de error predefinida a nivel de paquete que representa una condición de error específica. A diferencia de crear nuevos errores cada vez con errors.New, los errores centinela se declaran una vez y se reutilizan en todo el código.

Los errores centinela se definen como variables a nivel de paquete, normalmente con nombres que empiezan por Err:

package user

import "errors"

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

Las funciones devuelven estos errores predefinidos cuando ocurren condiciones específicas:

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

El poder de los errores centinela es que quienes realizan las llamadas pueden verificar condiciones de error específicas comparando directamente los valores de error:

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

La biblioteca estándar de Go utiliza errores centinela extensamente. Por ejemplo, io.EOF señala el fin de la entrada, y sql.ErrNoRows indica un resultado de consulta vacío. Este patrón crea un contrato claro entre los paquetes y sus usuarios sobre qué errores esperar.

Sin embargo, las comprobaciones de igualdad simples fallan cuando los errores están envueltos. En la siguiente lección, aprenderás cómo errors.Is() resuelve este problema comprobando toda la cadena de errores.

challenge icon

Desafío

Fácil

Construyamos un sistema de gestión de inventario que use errores centinela para comunicar condiciones de fallo específicas. Definirás variables de error a nivel de paquete que los llamadores puedan comprobar para gestionar adecuadamente distintos escenarios.

Organizarás tu código en dos archivos:

  • inventory.go: Crea un sistema de inventario con errores centinela predefinidos para casos de fallo comunes.

    Define tres errores centinela a nivel de paquete:

    • ErrItemNotFound con el mensaje "item not found in inventory"
    • ErrOutOfStock con el mensaje "item is out of stock"
    • ErrInsufficientQuantity con el mensaje "insufficient quantity available"

    Crea una estructura Inventory que contenga un mapa de nombres de artículos a sus cantidades. Implementa estos métodos:

    • NewInventory() *Inventory - crea un inventario vacío
    • AddItem(name string, quantity int) - añade o actualiza la cantidad de un artículo
    • GetQuantity(name string) (int, error) - devuelve la cantidad de un artículo o ErrItemNotFound si no existe
    • Purchase(name string, quantity int) error - intenta comprar artículos. Devuelve ErrItemNotFound si el artículo no existe, ErrOutOfStock si la cantidad actual es cero o ErrInsufficientQuantity si la cantidad solicitada supera las existencias disponibles. Si la operación tiene éxito, reduce el inventario y devuelve nil.
  • main.go: Lee las operaciones del inventario desde la entrada y demuestra cómo los llamadores pueden comprobar errores centinela específicos mediante una comparación directa de igualdad.

    Lee el nombre del artículo y la cantidad que se va a comprar desde la entrada. Crea un inventario, añade el artículo "laptop" con una cantidad de 5 y, después, intenta realizar la compra. Según el error devuelto, imprime un mensaje específico que demuestre que identificaste qué error centinela se produjo.

Se proporcionarán las siguientes entradas:

  • Línea 1: Nombre del artículo que se va a comprar
  • Línea 2: Cantidad que se va a comprar

Gestiona el resultado comprobando qué error específico se devolvió:

  • Si err == ErrItemNotFound: imprime Error: Item '[name]' does not exist in our inventory
  • Si err == ErrOutOfStock: imprime Error: Item '[name]' is currently out of stock
  • Si err == ErrInsufficientQuantity: imprime Error: Cannot purchase [quantity] units of '[name]' - not enough in stock
  • Si la operación tiene éxito: imprime Successfully purchased [quantity] units of '[name]'

Por ejemplo, dadas laptop y 3, tu salida debería ser:

Successfully purchased 3 units of 'laptop'

Y dadas phone y 2, tu salida debería ser:

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

Y dadas laptop y 10, tu salida debería ser:

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

Pruébalo tú mismo

package main

import (
	"fmt"
)

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

	// Crear inventario y añadir "laptop" con cantidad 5
	inv := NewInventory()
	inv.AddItem("laptop", 5)

	// TODO: Intentar comprar el artículo
	// Llamar a inv.Purchase(itemName, quantity)

	// TODO: Comprobar qué error centinela específico se devolvió utilizando una comparación de igualdad directa
	// Usar sentencias if/else if para comprobar:
	// - err == ErrItemNotFound
	// - err == ErrOutOfStock
	// - err == ErrInsufficientQuantity
	// - err == nil (éxito)

	// TODO: Imprimir el mensaje apropiado basado en el error
	// Si ErrItemNotFound: fmt.Printf("Error: Item '%s' does not exist in our inventory\n", itemName)
	// Si ErrOutOfStock: fmt.Printf("Error: Item '%s' is currently out of stock\n", itemName)
	// Si ErrInsufficientQuantity: fmt.Printf("Error: Cannot purchase %d units of '%s' - not enough in stock\n", quantity, itemName)
	// Si tiene éxito: fmt.Printf("Successfully purchased %d units of '%s'\n", quantity, itemName)
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Go online