DMarlon Studio

Lección 13 · 13 de 20

Errores como valores · Go

Trate los errores en Go como valores: créelos con errors.New y fmt.Errorf, compruébelos con if err != nil y reconózcalos con errors.Is.

Go · Errores como valores en DMarlon Studio: el código del ejemplo y su salida en la terminal

Go no tiene excepciones: una función que puede fallar devuelve un error como último resultado. withdraw devuelve el saldo nuevo y un error; si todo va bien, el error es nil, es decir, «ningún error».

errors.New("insufficient funds") crea un error con un mensaje. Guardado en la variable ErrNoFunds, es un error centinela: un valor conocido con el que se puede comparar después. fmt.Errorf crea un error con formato, igual que Printf: invalid amount -5.00.

Con %w, fmt.Errorf envuelve otro error: el mensaje añade detalle (withdraw 90.00: insufficient funds), pero el error original sigue dentro. errors.Is(err, ErrNoFunds) lo busca, y por eso da true para la retirada de 90 euros y false para la cantidad negativa.

Quien llama comprueba siempre: if err != nil. Si hay error, lo escribe y, con continue, pasa a la cantidad siguiente sin tocar el saldo; si no, guarda newBalance. Así, de 100 euros se sacan 30 y luego 45, y quedan 25.00.

Código · main.go

package mainimport (	"errors"	"fmt")// errors.New creates an error value that can be recognised later.var ErrNoFunds = errors.New("insufficient funds")// The error goes last; nil means that everything went well.func withdraw(balance, amount float64) (float64, error) {	switch {	case amount <= 0:		return balance, fmt.Errorf("invalid amount %.2f", amount)	case amount > balance:		return balance, fmt.Errorf("withdraw %.2f: %w", amount, ErrNoFunds) // %w wraps it	}	return balance - amount, nil}func main() {	balance, amounts := 100.0, []float64{30, -5, 90, 45}	for i := 0; i < len(amounts); i++ {		newBalance, err := withdraw(balance, amounts[i])		if err != nil {			fmt.Println("Error:", err)			fmt.Println("  is ErrNoFunds?", errors.Is(err, ErrNoFunds))			continue		}		balance = newBalance		fmt.Printf("Took %.2f, balance %.2f\n", amounts[i], balance)	}}

Salida · go run main.go

Took 30.00, balance 70.00
Error: invalid amount -5.00
  is ErrNoFunds? false
Error: withdraw 90.00: insufficient funds
  is ErrNoFunds? true
Took 45.00, balance 25.00

Para recordar

  • El error es el último resultado; nil significa que no hubo error.
  • errors.New crea un error; fmt.Errorf, uno con formato.
  • %w envuelve un error dentro de otro.
  • errors.Is reconoce un error aunque esté envuelto.
  • Compruebe siempre con if err != nil.

Ejercicio

Añada un límite diario: un error centinela ErrDailyLimit que withdraw devuelva, envuelto con %w, si la cantidad supera 60 euros, y compruébelo en main con errors.Is.