Menu
Coddy logo textTech

La interfaz error

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy — lección 52 de 107.

En Go, los errores se manejan a través de una interfaz integrada llamada error. Esta interfaz es notablemente simple: requiere solo un método:

type error interface {
    Error() string
}

Cualquier tipo que implemente un método Error() que devuelva un string satisface automáticamente la interfaz error. Este es el sistema de interfaces de Go en funcionamiento: no se requiere una declaración explícita.

La forma más común de crear errores es utilizando el paquete errors:

import "errors"

func Divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return a / b, nil
}

Las funciones de Go suelen devolver un error como su último valor de retorno. Cuando no ocurre ningún error, se devuelve nil. El llamador entonces comprueba si el error es distinto de nil antes de continuar:

result, err := Divide(10, 0)
if err != nil {
    fmt.Println("Error:", err.Error())
    return
}
fmt.Println("Result:", result)

También puedes usar fmt.Errorf para crear mensajes de error con formato:

func GetUser(id int) (string, error) {
    if id <= 0 {
        return "", fmt.Errorf("invalid user id: %d", id)
    }
    return "Alice", nil
}

Este patrón de devolver errores en lugar de lanzar excepciones es fundamental en Go. Hace que el manejo de errores sea explícito y te obliga a considerar qué sucede cuando las cosas salen mal, un aspecto clave para escribir código robusto y orientado a objetos.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de cuenta bancaria que demuestre el patrón de manejo de errores de Go. Crearás una cuenta sencilla que valide las operaciones y devuelva errores significativos cuando algo salga mal.

Organizarás tu código en dos archivos:

  • account.go: Crea una estructura BankAccount con un campo exportado Owner (string) y un campo no exportado balance (float64). Implementa lo siguiente:
    • NewBankAccount(owner string, initialDeposit float64) (*BankAccount, error): un constructor que devuelve un error con el mensaje "initial deposit must be positive" si el depósito inicial es cero o negativo. De lo contrario, crea y devuelve la cuenta.
    • Deposit(amount float64) error: añade dinero al saldo. Devuelve un error con el mensaje "deposit amount must be positive" si el monto es cero o negativo.
    • Withdraw(amount float64) error: retira dinero del saldo. Devuelve un error con el mensaje "withdrawal amount must be positive" si el monto es cero o negativo, o "insufficient funds" si el saldo es menor que el monto del retiro.
    • Balance() float64: devuelve el saldo actual.
  • main.go: Lee los detalles de la cuenta y los montos de las transacciones desde la entrada. Intenta crear una cuenta y realizar operaciones. Después de cada operación, imprime el mensaje de éxito o el mensaje de error.

Se proporcionarán las siguientes entradas:

  • Línea 1: Nombre del propietario (Owner)
  • Línea 2: Monto del depósito inicial
  • Línea 3: Monto del depósito
  • Línea 4: Monto del retiro

Para cada operación, imprime el resultado:

  • Después de la creación de la cuenta: Account created for [Owner] with balance: $[balance] o Error: [error message]
  • Después del depósito: Deposited successfully. New balance: $[balance] o Error: [error message]
  • Después del retiro: Withdrew successfully. New balance: $[balance] o Error: [error message]

Formatea todos los valores de saldo con dos decimales. Si la creación de la cuenta falla, omite las operaciones restantes.

Por ejemplo, dados Alice, 100, 50 y 200, tu salida debería ser:

Account created for Alice with balance: $100.00
Deposited successfully. New balance: $150.00
Error: insufficient funds

Y dados Bob, -50, 25 y 10, tu salida debería ser:

Error: initial deposit must be positive

Hoja de referencia

Go maneja los errores a través de la interfaz integrada error, la cual requiere un único método:

type error interface {
    Error() string
}

Crea errores utilizando el paquete errors:

import "errors"

func Divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return a / b, nil
}

Las funciones devuelven errores como el último valor de retorno. Devuelve nil cuando no ocurre ningún error:

result, err := Divide(10, 0)
if err != nil {
    fmt.Println("Error:", err.Error())
    return
}
fmt.Println("Result:", result)

Usa fmt.Errorf para mensajes de error con formato:

func GetUser(id int) (string, error) {
    if id <= 0 {
        return "", fmt.Errorf("invalid user id: %d", id)
    }
    return "Alice", nil
}

Pruébalo tú mismo

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Leer el nombre del propietario
	ownerName, _ := reader.ReadString('\n')
	ownerName = strings.TrimSpace(ownerName)

	// Leer el depósito inicial
	initialDepositStr, _ := reader.ReadString('\n')
	initialDeposit, _ := strconv.ParseFloat(strings.TrimSpace(initialDepositStr), 64)

	// Leer el monto del depósito
	depositStr, _ := reader.ReadString('\n')
	depositAmount, _ := strconv.ParseFloat(strings.TrimSpace(depositStr), 64)

	// Leer el monto del retiro
	withdrawStr, _ := reader.ReadString('\n')
	withdrawAmount, _ := strconv.ParseFloat(strings.TrimSpace(withdrawStr), 64)

	// TODO: Crear una nueva cuenta bancaria usando NewBankAccount
	// Si hay un error, imprime "Error: [error message]" y retorna
	// Si tiene éxito, imprime "Account created for [Owner] with balance: $[balance]"

	// TODO: Intentar depositar el monto del depósito
	// Si hay un error, imprime "Error: [error message]"
	// Si tiene éxito, imprime "Deposited successfully. New balance: $[balance]"

	// TODO: Intentar retirar el monto del retiro
	// Si hay un error, imprime "Error: [error message]"
	// Si tiene éxito, imprime "Withdrew successfully. New balance: $[balance]"

	// Recuerda formatear los valores de balance con dos decimales usando fmt.Printf("%.2f", balance)

	_ = ownerName
	_ = initialDeposit
	_ = depositAmount
	_ = withdrawAmount
}
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