Vectores/Arrays, Slices y Maps
Last updated
Last updated
En programación se conoce vector o arreglo a una zona de almacenamiento contiguo que contiene una serie de elementos del mismo tipo, los elementos de la matriz. Desde el punto de vista lógico una matriz se puede ver como un conjunto de elementos ordenados en fila (o filas y columnas si tuviera dos dimensiones).
Al ser de tamaño fijo, los arrays aseguran que se utilice únicamente la cantidad de memoria necesaria, optimizando así el uso de recursos.
La sintaxis es así:
Donde nombre_array
es el nombre del array, longitud
es la cantidad de elementos que puede almacenar el array y tipo
es el tipo de dato que contendrá el
Ejemplo de un Array en GO →
Arrays:
Tamaño fijo en el momento de la declaración
Menos flexibles que los slices
Útiles cuando se conoce el tamaño requerido previamente
Slices:
Tamaño dinámico y puede cambiar durante la ejecución del programa
Más flexibles que los arrays
Útiles cuando se desconoce el tamaño requerido previamente o cuando se espera que cambie
Para recorrer todos los elementos de un array, puedes utilizar un bucle for
. Go proporciona dos formas de iterar sobre un array: utilizando un bucle for
con índices y utilizando un bucle for
con la declaración range.
Bucle for con índices
Bucle for
con la declaración range
En Go, los tres puntos (
...
) en una declaración de un array indican que el tamaño del array debe ser inferido automáticamente a partir de los elementos que le asignes. No es exactamente lo mismo que tener un "tamaño variable", sino que el compilador determina el tamaño del array con base en la cantidad de elementos proporcionados en la lista de inicialización.
Ahora que ya sabemos lo que es un array
en Go entender lo que es un slice
no debería suponer problema alguno. Si recuerdas, en el apartado anterior aclaraba que los arreglos tienen un tamaño fijo, y pudieron notar que su capacidad y longitud coincidían, por lo posiblemente se estén cuestionando la utilidad de conocer el valor de capacidad. Los slices pueden verse como arreglos de longitud dinámica, siendo un poco más técnicos, un slice apunta a un array, claro que aún no hablamos de punteros, estoy preparando una publicación específica para ellos, por el momento no se preocupen.
Por ejemplo, para crear un slice de tipo int
con una longitud inicial de 3
elementos y una capacidad máxima de 5
elementos:
En este ejemplo, se crea un slice llamado mi_slice
de tipo int
con una longitud inicial de 3
elementos y una capacidad máxima de 5
elementos.
Para agregar elementos a un slice, se utiliza la función append(). La sintaxis para agregar un elemento a un slice es la siguiente:
La longitud de un slice se puede obtener utilizando la función len() y la capacidad del slice se puede obtener utilizando la función cap().
Por ejemplo, para obtener la longitud y la capacidad de mi_slice
:
Los mapas se definen usando la palabra clave map
seguida del tipo de dato de la clave y del tipo de dato del valor.
Se pueden añadir elementos a un mapa utilizando la sintaxis clave:valor
.
Se puede recuperar un valor de un mapa utilizando la clave como índice.
Se puede eliminar un elemento de un mapa utilizando la función delete
.
Se puede comprobar si una clave existe en un mapa utilizando la función len
.
Se puede recorrer un mapa utilizando un bucle for
.
No es posible ordenar un mapa directamente en GO. Sin embargo, existen diferentes técnicas para obtener un ordenamiento, como convertir el mapa a una lista y luego ordenarla.
Los mapas se pueden serializar a diferentes formatos como JSON o XML.
Un array es una secuencia contigua de elementos del mismo tipo y de tamaño fijo, lo que significa que no puedes cambiar su longitud una vez declarado.
Declaración:
Inicialización directa: Puedes inicializar el array al declararlo:
Características importantes:
El tamaño es parte del tipo, por lo que [3]int
y [5]int
son tipos diferentes.
Los arrays no son dinámicos, por lo que no puedes agregar o quitar elementos.
Acceso y mutabilidad: Los arrays son mutables, lo que significa que puedes modificar sus elementos directamente usando el índice:
Los slices son una abstracción más flexible y poderosa que los arrays. A diferencia de los arrays, los slices tienen un tamaño dinámico y pueden crecer o reducirse.
Inicialización: Puedes crear un slice a partir de un array o directamente:
Slice a partir de un array:
Capacidad y longitud: Los slices tienen dos propiedades importantes: la longitud (len
) y la capacidad (cap
):
La capacidad indica cuántos elementos se pueden agregar antes de que el slice necesite redimensionarse.
Copiar slices: Para copiar un slice en otro
Aquí, make
se usa para crear un slice vacío con una longitud específica.
Cortar slices (slicing) Puedes crear sub-slices dinámicos de un slice:
Compartir memoria, Los slices comparten el mismo array subyacente, por lo que cambiar el valor en un slice afecta a los otros slices creados del mismo array:
Redimensionar slices, El redimensionamiento de un slice puede crear un nuevo array, lo que tiene un costo en rendimiento cuando se manejan grandes cantidades de datos. Es recomendable predefinir la capacidad de un slice si se sabe cuántos elementos se van a almacenar.
Append y redimensionamiento:
Reducir un slice: Eliminar elementos de un slice sin perder la referencia
¿Cuál es la diferencia entre la longitud y la capacidad de un slice?
¿Qué ocurre cuando modificas un slice que proviene de un array?
Si creas un slice desde un array, ¿modificar el slice afecta el array original? Explica por qué.
Escribe una función que acepte un slice de enteros y devuelva el promedio de esos enteros.
¿Qué hace la función append()
internamente si se excede la capacidad del slice?
Cuando estés listo, seguimos con el siguiente tema.
Respuestas:
Correcto. La longitud (len
) es el número de elementos que actualmente contiene el slice, mientras que la capacidad (cap
) es el número de elementos que puede contener antes de que Go redimensione el slice.
Parcialmente correcto. Modificar un slice afecta al array original si el slice aún está basado en el array subyacente. Los slices no son independientes del array; al contrario, comparten memoria. Así que, si modificas un slice, esos cambios se reflejan en el array original.
Incorrecto. Los slices no son copias del array original. Si creas un slice a partir de un array, ambos compartirán la misma memoria. Modificar el slice también modifica el array original, ya que ambos están referenciando la misma región de memoria.
Código incorrecto. En tu función, hay algunos problemas:
No has inicializado la variable suma
.
Estás usando índices incorrectos dentro del loop.
Además, la función debería devolver float64
porque estamos calculando un promedio.
Aquí te dejo la corrección:
Incorrecto. Cuando append()
excede la capacidad del slice, no retorna un error ni un panic
. En lugar de eso, Go crea un nuevo array con mayor capacidad, copia los elementos del array original a este nuevo array, y luego agrega el nuevo elemento. El slice devuelto apunta a este nuevo array.
¿Cómo puedes asegurarte de que un slice tiene suficiente capacidad antes de agregarle nuevos elementos?
¿Cuál es la diferencia entre declarar un slice con var
y crearlo con make
?
¿Qué ventaja tiene usar copy()
en slices en lugar de hacer la asignación directa?
¿Cómo puedes reducir la capacidad de un slice sin cambiar su longitud actual?
Respuestas:
Correcto, puedes asegurarte de que un slice tenga suficiente capacidad al usar make()
y especificar la capacidad adecuada. Sin embargo, si no sabes con exactitud cuántos elementos agregarás, puedes optar por sobreasignar capacidad o monitorear el uso de append()
para manejar redimensionamientos automáticos.
Correcto. La diferencia entre var
y make()
es fundamental:
Usar var
simplemente declara el slice, pero no le asigna memoria ni capacidad.
Usar make()
sí reserva memoria para el array subyacente y asigna tanto longitud como capacidad, garantizando que el slice esté completamente inicializado y listo para usar.
Incorrecto en parte. El uso de copy()
no hace que los slices compartan la misma dirección de memoria. De hecho, copy()
crea una copia de los valores en un nuevo espacio en memoria. La ventaja de usar copy()
es que puedes duplicar los valores de un slice en otro slice sin que ambos compartan la misma memoria, lo que es útil si no quieres que los cambios en un slice afecten al otro.
Correcto, puedes reducir la longitud de un slice cambiando sus límites como en el ejemplo que diste. Sin embargo, esto solo afecta la longitud, no la capacidad. Si quieres reducir la capacidad, podrías usar copy()
para copiar los valores en un nuevo slice con menor capacidad.
¿Qué sucede si haces un slice de un array y luego expandes el slice más allá de la capacidad del array original?
Si tienes un slice A
y creas un nuevo slice B
a partir de él (sin usar copy()
), ¿qué sucede cuando modificas el contenido del slice B
?
¿Cómo puedes inicializar un slice de longitud y capacidad cero usando make()
?
¿Cuál es la diferencia en comportamiento entre un slice vacío []int{}
y un slice nil
en Go?
Respuestas:
Incorrecto en parte. Si intentas expandir un slice más allá de la capacidad del array original con append()
, Go creará un nuevo array que pueda acomodar los nuevos elementos, y el slice comenzará a referenciar este nuevo array. El array original permanece sin cambios. No habrá un error, simplemente se asignará un nuevo array en memoria si la capacidad se supera.
Correcto, si creas un nuevo slice a partir de otro sin usar copy()
, ambos slices compartirán el mismo array subyacente. Por lo tanto, modificar uno de los slices afectará al otro, ya que apuntan a la misma memoria.
Correcto, has definido un slice con longitud y capacidad cero correctamente con make([]int, 0, 0)
.
Correcto, un slice vacío ([]int{}
) está inicializado pero no contiene elementos, mientras que un slice nil
no ha sido inicializado en absoluto. Un slice nil
tiene longitud y capacidad cero, pero también su referencia es nula, mientras que el slice vacío ya tiene una referencia asignada.
Los mapas en GO son una herramienta poderosa para almacenar y recuperar datos de forma eficiente. Dominar las diferentes características de los mapas te ayudará a crear programas más robustos y escalables.
Aunque los arrays y los en Go pueden parecer similares a simple vista, hay diferencias clave entre ellos:
A continuación, se muestra un ejemplo de array y en Go para ilustrar las diferencias: