Sobes.tech
Middle

¿Cómo funciona un Map en Go?

sobes.tech AI

Respuesta de la IA

Map en Go se implementa como una tabla hash.

Los componentes principales de la estructura map:

  • Función hash: Mapea las claves a valores hash (números enteros).
  • Array de buckets: Conjunto de listas o arrays donde se almacenan pares clave-valor. El índice del bucket se determina por el valor hash de la clave.
  • Manejo de colisiones: Cuando diferentes claves tienen el mismo hash (colisión), los elementos con esas claves se almacenan en un mismo bucket, generalmente en forma de lista enlazada o en un bucket de overflow.
  • Factor de carga: Relación entre el número de elementos y el número de buckets. Cuando se supera un umbral, se realiza un rehashing: se crea un nuevo array de buckets más grande y se mueven todos los elementos de los buckets antiguos a los nuevos.

La estructura map en Go está representada por el tipo hmap:

 type hmap struct {
    count     int // Número de elementos
    flags     uint8 // Flags de estado
    B         uint8 // log_2 del número de buckets (número de buckets es 2^B)
    noverflow uint16 // Número de buckets con overflow (solo para estadísticas)
    hash0     uint32 // Valor inicial de la función hash

    buckets    unsafe.Pointer // Puntero al array de buckets (principal y overflow)
    oldbuckets unsafe.Pointer // Puntero al array antiguo de buckets durante la migración
    nevacuate  uintptr // Indica hasta qué bucket antiguo se ha completado la migración

    extra *mapextra // Información adicional (opcional)
}

 type mapextra struct {
    overflow    *[2]*[]*bmap // Punteros a arrays de buckets con overflow
    oldoverflow *[2]*[]*bmap // Punteros a antiguos arrays de buckets con overflow
    nextOverflow *bmap // Siguiente bucket de overflow libre
}

 type bmap struct {
    tophash [8]uint8 // Top hash (bits superiores del hash) para acelerar la búsqueda en el bucket
    // A continuación se encuentran las claves, valores y punteros a los siguientes bmap (si el bucket está lleno)
    // distribuir todos los datos para hmap.buckets en un solo bloque malloc
    // ver ../../runtime/map.go para detalles
}

Operaciones:

  • Inserción/Actualización: Se calcula el hash de la clave, se determina el bucket. Si la clave ya existe, se actualiza el valor. Si no, se añade el par clave-valor al bucket. En caso de overflow o superación del Load Factor, puede ocurrir un rehashing.
  • Búsqueda: Se calcula el hash de la clave, se determina el bucket. Se recorren los elementos en el bucket por top-hash, luego se comparan las claves completas. Se devuelve el valor y un indicador de existencia.
  • Eliminación: Se calcula el hash de la clave, se determina el bucket. El elemento se marca como eliminado (pero no se elimina inmediatamente de la memoria). La eliminación se realiza en operaciones posteriores o durante el rehashing.

El mapa en Go no es sincronizado y no puede ser utilizado de forma segura por múltiples goroutines sin sincronización externa.