Saltar al contenido principal
Go

Go: panic: runtime error: index out of range y errores comunes

Cómo resolver los errores más frecuentes en Go: index out of range, nil pointer dereference, interface conversion y deadlock.

Error: error[E0502]: cannot borrow as mutable because it is also borrowed as immutable

¿Por qué ocurre?

Los errores más frecuentes en Go son panics de runtime que ocurren porque: - **index out of range**: acceder a un índice que no existe en un slice o array - **nil pointer dereference**: llamar a un método o campo de un puntero nil - **interface conversion failed**: hacer type assertion incorrecta sin verificar - **concurrent map writes**: escritura concurrente en un map sin mutex - **send on closed channel**: enviar datos a un canal ya cerrado

Solución paso a paso

1. index out of range

// ❌ Panic si el slice tiene menos de 3 elementos
nombres := []string{"Ana", "Bea"}
fmt.Println(nombres[2]) // panic: runtime error: index out of range [2] with length 2

// ✅ Verificar longitud antes de acceder if len(nombres) > 2 { fmt.Println(nombres[2]) }

// ✅ Iterar con range (nunca puede ir fuera de rango) for i, nombre := range nombres { fmt.Printf("%d: %s\n", i, nombre) }

2. nil pointer dereference

// ❌ Panic si el usuario es nil
type Usuario struct {
    Nombre string
}

func mostrarNombre(u *Usuario) { fmt.Println(u.Nombre) // panic si u es nil }

// ✅ Verificar nil antes de usar el puntero func mostrarNombre(u *Usuario) { if u == nil { fmt.Println("Usuario no encontrado") return } fmt.Println(u.Nombre) }

3. Type assertion con verificación

var i interface{} = "hola"

// ❌ Panic si no es string s := i.(string)

// ✅ Usar el patrón "comma ok" s, ok := i.(string) if !ok { log.Println("No es un string") return } fmt.Println(s)

// ✅ Usar type switch para múltiples tipos switch v := i.(type) { case string: fmt.Println("String:", v) case int: fmt.Println("Int:", v) default: fmt.Printf("Tipo desconocido: %T\n", v) }

4. Concurrent map writes — usar sync.RWMutex

import "sync"

type SafeMap struct { mu sync.RWMutex data map[string]string }

func (m *SafeMap) Set(key, value string) { m.mu.Lock() defer m.mu.Unlock() m.data[key] = value }

func (m *SafeMap) Get(key string) (string, bool) { m.mu.RLock() defer m.mu.RUnlock() val, ok := m.data[key] return val, ok }

// O usar sync.Map directamente var m sync.Map m.Store("clave", "valor") val, ok := m.Load("clave")

5. Manejo de errores idiomático en Go

// Go usa errores explícitos, no excepciones
func dividir(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("división por cero")
    }
    return a / b, nil
}

// ✅ Siempre verificar el error resultado, err := dividir(10, 0) if err != nil { log.Printf("Error al dividir: %v", err) return } fmt.Println(resultado)

6. Recuperar de un panic (defer + recover)

func operacionSegura() (resultado string, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("panic recuperado: %v", r)
        }
    }()

// Código que podría hacer panic resultado = hacerAlgo() return }

Cómo evitarlo en el futuro

- Verifica siempre `len(slice) > índice` antes de acceder por índice - Usa `if val == nil` antes de desreferenciar punteros - Prefiere el patrón `val, ok := interface.(Tipo)` para type assertions - Usa `go race detector` para detectar race conditions: `go test -race ./...` - Maneja siempre los errores: nunca uses `_` para ignorar un error en producción

GoGolangpanicnil pointererrores runtime

¿Quieres que una IA te ayude? Genera el prompt perfecto para tu error:

Generador de Prompts

¿Necesitas desarrollo a medida?

Apps web, IA, módulos ERP — cuéntame tu proyecto.