Envoltorio y desenvoltorio de errores
Uso de %w, errors.Is y errors.As
Envoltorio y desenvoltorio de errores es una lección gratuita de Go Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Go Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Go Academy incluye 4 lecciones en total.
¿Qué es el envoltorio de errores?
El envoltorio de errores inserta un error original dentro de un error nuevo y conserva el original para su inspección mediante código, a la vez que añade contexto. Se introdujo correctamente en Go 1.13:
package main
import ("fmt"; "errors")
var ErrDB = errors.New("database unreachable")
func queryUsers() error {
return fmt.Errorf("queryUsers: %w", ErrDB)
}
func loadProfile(id int) error {
return fmt.Errorf("loadProfile(%d): %w", id, queryUsers())
}
func main() {
err := loadProfile(42)
fmt.Println(err) // loadProfile(42): queryUsers: database unreachable
}El verbo %w
Utilice %w (no %v) en fmt.Errorf para envolver un error. El error envuelto está disponible mediante errors.Unwrap:
package main
import ("fmt"; "errors")
func main() {
inner := errors.New("inner error")
outer := fmt.Errorf("outer: %w", inner)
fmt.Println(outer) // outer: inner error
fmt.Println(errors.Unwrap(outer)) // inner error
fmt.Println(errors.Is(outer, inner)) // true
}errors.Unwrap
errors.Unwrap devuelve el siguiente error de la cadena (el error envuelto) o nil si no hay ninguno:
package main
import ("fmt"; "errors")
type Layer struct{ msg string; err error }
func (l *Layer) Error() string { return l.msg }
func (l *Layer) Unwrap() error { return l.err }
func main() {
root := errors.New("root")
mid := &Layer{"mid", root}
top := &Layer{"top", mid}
fmt.Println(errors.Unwrap(top)) // mid
fmt.Println(errors.Unwrap(mid)) // root
fmt.Println(errors.Unwrap(root)) // <nil>
}errors.Is: recorrido de la cadena
errors.Is(err, target) desenvuelve la cadena de errores de forma recursiva hasta encontrar una coincidencia o llegar a nil:
package main
import ("fmt"; "errors")
var ErrNotFound = errors.New("not found")
func findItem(id int) error {
return fmt.Errorf("findItem(%d): %w",
id, fmt.Errorf("repo: %w", ErrNotFound))
}
func main() {
err := findItem(7)
fmt.Println(errors.Is(err, ErrNotFound)) // true — deep in chain
fmt.Println(err) // full message chain
}errors.As: recorrido de la cadena para tipos
errors.As(err, &target) recorre la cadena en busca de un error asignable al tipo de target:
package main
import ("fmt"; "errors")
type StatusError struct{ Code int }
func (e *StatusError) Error() string { return fmt.Sprintf("status %d", e.Code) }
func doRequest() error {
return fmt.Errorf("request: %w", &StatusError{503})
}
func main() {
err := doRequest()
var se *StatusError
if errors.As(err, &se) {
fmt.Println("status code:", se.Code) // 503
}
}Unwrap personalizado para cadenas
Implemente Unwrap() error en su tipo de error personalizado para admitir errors.Is y errors.As:
package main
import ("fmt"; "errors")
type AppError struct {
Op string
Err error
}
func (e *AppError) Error() string { return fmt.Sprintf("%s: %v", e.Op, e.Err) }
func (e *AppError) Unwrap() error { return e.Err }
var ErrAuth = errors.New("unauthorized")
func main() {
err := &AppError{"login", ErrAuth}
fmt.Println(errors.Is(err, ErrAuth)) // true
}%v frente a %w en fmt.Errorf
La diferencia entre %v y %w:
package main
import ("fmt"; "errors")
func main() {
inner := errors.New("inner")
withV := fmt.Errorf("outer: %v", inner) // string only, no wrap
withW := fmt.Errorf("outer: %w", inner) // wraps inner
fmt.Println(errors.Is(withV, inner)) // false — not wrapped
fmt.Println(errors.Is(withW, inner)) // true — wrapped
}Envolver errores en la práctica: controlador HTTP
Envolver los errores de forma coherente facilita la depuración en sistemas de producción:
package main
import "fmt"
func dbQuery(sql string) error {
return fmt.Errorf("db.Query(%q): connection refused", sql)
}
func getUserByID(id int) (string, error) {
if err := dbQuery("SELECT * FROM users WHERE id=?"); err != nil {
return "", fmt.Errorf("getUserByID(%d): %w", id, err)
}
return "Alice", nil
}
func handler() error {
_, err := getUserByID(1)
if err != nil {
return fmt.Errorf("handler: %w", err)
}
return nil
}
func main() { fmt.Println(handler()) }errors.Join: múltiples envoltorios (Go 1.20+)
errors.Join crea un error que envuelve varios errores. errors.Is los comprueba todos:
package main
import ("fmt"; "errors")
var ErrA = errors.New("err A")
var ErrB = errors.New("err B")
func main() {
joined := errors.Join(ErrA, ErrB)
fmt.Println(joined)
fmt.Println(errors.Is(joined, ErrA)) // true
fmt.Println(errors.Is(joined, ErrB)) // true
}Prácticas recomendadas para desenvolver errores
Directrices para envolver errores:
- Envuelva con
%wpara conservar el error y permitir su inspección mediante código - Añada el nombre de la operación como contexto:
fmt.Errorf("funcName: %w", err) - No envuelva errores centinela si los llamadores no van a utilizar
errors.Is - Evite envolver dos veces el mismo contexto en cada nivel
- Implemente
Unwrap()en los tipos personalizados para que participen en las cadenas
Comprobación rápida
¿Cuál es la diferencia entre utilizar %v y %w en fmt.Errorf?
Repaso: envolver y desenvolver errores
Resumen:
fmt.Errorf("ctx: %w", err)envuelve con contextoerrors.Unwrapobtiene el siguiente error de la cadenaerrors.Isrecorre la cadena para buscar una coincidencia de identidaderrors.Asrecorre la cadena para buscar una coincidencia de tipo- Los tipos personalizados implementan
Unwrap() error errors.Joinenvuelve varios errores (Go 1.20+)
Preguntas frecuentes
¿La lección «Envoltorio y desenvoltorio de errores» es gratis?
Sí — el texto completo de «Envoltorio y desenvoltorio de errores» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Go Academy, actualiza a CoddyKit PRO. El curso de Go Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Envoltorio y desenvoltorio de errores»?
Uso de %w, errors.Is y errors.As Practicas Go Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Go Academy?
No se requiere experiencia previa. Go Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Envoltorio y desenvoltorio de errores»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Go Academy?
Sí. Cada lección de Go Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- La interfaz error
- Creación de errores personalizados
- Envoltorio y desenvoltorio de errores
- panic, recover y defer