Es tiempo de continuar con la serie de publicaciones dedicadas al lenguaje Go. Sé que hace más de una semana que publiqué el último, me disculpo por eso, ahora a compensar el retraso.
Arreglos
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).
Fuente: Wikipedia
Si no conocen los arreglos, recomiendo investigar un poco más al respecto para sacar el mayor provecho de esta publicación, debido a que me limitaré a explicar como funciona específicamente en el lenguaje Go.
Hasta ahora hemos visto tipos de datos sencillos como Números enteros, Decimales, Cadenas de texto y Booleanos, abordando, con estos, algunas características del lenguaje. Pero en ocasiones es necesario agrupar valores con cierta relación, por ejemplo un conjunto de nombres; basado en lo que hemos aprendido podríamos hacer algo como lo siguiente.
var nombre1 = "Ana"
var nombre2 = "José"
var nombre3 = "Daniel"
var nombre4 = "María"
var nombre5 = "Carlos"
Bueno, eso podría funcionar, pero quizás necesiten 10 valores, o 20, o no conozcan exactamente cuantos valores van a necesitar. En esos casos los arreglos son muy útiles. Retomemos el ejemplo anterior.
var nombres [5]string
nombres[0] = "Ana"
nombres[1] = "José"
nombres[2] = "Daniel"
nombres[3] = "María"
nombres[4] = "Carlos"
Es posible que estén pensando que es prácticamente lo mismo y ahora hasta toca escribir una línea más. En parte tienen razón, en este caso quizás una sintaxis como las siguiente resulte más práctica.
nombres := [5]string{"Ana", "José", "Daniel", "María", "Carlos"}
Supongo que ya conocen las declaración corta; en ambos casos estamos declarando una variable con el identificador nombres
que contiene un arreglo de 5 elementos de tipo string
. Es importante saber que los arreglos en Go sólo pueden contener elementos de un mismo tipo, en este caso cadenas de texto, además que su tamaño es fijo. Veámos un ejemplo para comprobarlo.
var numeros [10]int
fmt.Println(numeros) // [0 0 0 0 0 0 0 0 0 0]
Si recuerdan, al declarar una variable Go le da su valor cero como valor inicial, en este caso, al ser un arreglo de 10 elementos de tipo int
, se crea un arreglo con 10 ceros, siendo 0 el valor cero, valga la redundancia, de las variables de tipo int
; tal como en el primer ejemplo, podemos acceder y modificar cada valor en el Arreglo a través de su indice, el cual comienza a enumerarse desde el 0, es decir, siendo este un arreglo de 10 valores, el indice del último valor sería 9. Veamos un ejemplo de esto.
numeros[0] = 6
numeros[2] = 9
numeros[5] = 18
numeros[9] = 15
n := numeros[5]
fmt.Println("El valor de n es", n) // El valor de n es 18
fmt.Println(numeros) // [6 0 9 0 0 18 0 0 0 15]
Como pueden ver, a través de la sintaxis de corchetes podemos acceder al valor en la posición correspondiente en el arreglo tanto para asignar un nuevo valor como para realizar una operación con él, como asignarlo a otra variable. Otra característica interesante es que podemos acceder tanto a la longitud de un arreglo como a su capacidad (hablaré un poco mas al respecto en la siguiente parte) haciendo uso de las funciones integradas len
y cap
respectivamente.
fmt.Println(len(numeros)) // 10
fmt.Println(cap(numeros)) // 10
Esto es muy útil, por ejemplo, para acceder al último elemento en un arreglo, sin importar su longitud sabemos que su último indice coincide con el valor de su longitud menos uno, en el caso del presente ejemplo: len(numeros) – 1
.
Slices
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. Veamos un ejemplo.
nombresArray := [5]string{"Ana", "José", "Daniel", "María", "Carlos"}
nombresSlice := nombresArray[0:3]
fmt.Println(nombresSlice) // [Ana José Daniel]
fmt.Println(len(nombresSlice)) // 3
fmt.Println(cap(nombresSlice)) // 5
Con excepción del nombre el arreglo en la primera línea , se trata del mismo arreglo que vimos antes, la parte interesante es la siguiente línea, a la variable nombresSlice
se le asigna una porción de nombresArray
; la regla de los indices es la misma, el valor 0 hace referencia a la primera posición en el arreglo, el número 3 que se encuentra después de los dos puntos indican la posición final a la que deseamos acceder, sin embarco, esta no incluye al valor en dicha posición sino al anterior a este; por tal motivo, el valor en el indice 3, María, no se incluye en el nombresSlice
.
Si observamos ahora la salida de las últimas dos líneas, notaremos que, a diferencia del ejemplo con arreglos, los valores de longitud y capacidad no son iguales. Es decir, el valor de longitud es el esperado (3), pero la capacidad es de 5. Me parece que esto es más fácil de entender con un ejemplo.
nombresArray := [5]string{"Ana", "José", "Daniel", "María", "Carlos"}
nombresSlice := nombresArray[0:3]
fmt.Println(nombresSlice) // [Ana José Daniel]
fmt.Printf("len %d - cap %d\n", len(nombresSlice), cap(nombresSlice)) // len 3 - cap 5
nombresSlice = append(nombresSlice, "Antonio")
fmt.Printf("len %d - cap %d\n", len(nombresSlice), cap(nombresSlice)) // len 4 - cap 5
nombresSlice = append(nombresSlice, "Daniela")
fmt.Printf("len %d - cap %d\n", len(nombresSlice), cap(nombresSlice)) // len 5 - cap 5
nombresSlice = append(nombresSlice, "Carmen")
fmt.Printf("len %d - cap %d\n", len(nombresSlice), cap(nombresSlice)) // len 6 - cap 10
fmt.Println(nombresSlice) // [Ana José Daniel Antonio Daniela Carmen]
Por una parte estamos conociendo la función append
, creo que podrán suponer lo que hace, toma como primer argumento un slice
y por segundo a un valor o valores a ser añadidos al slice
y retorna un nuevo slice
con todos los valores del anterior además del nuevo valor. Por otra parte notamos que a medida que añadimos elementos al slice
su longitud se incrementa pero su capacidad se mantiene hasta que la longitud la supera, llegado a ese punto la capacidad del slice
se duplica. Ese es básicamente el comportamiento natural de los slice
. Perfecto, ahora sabemos que podemos crear un slice
a partir de un array
existente, pero esa no es la única manera, veamos otras opciones.
var numeros1 []int
numeros2 := []int{1, 2, 3, 4, 5, 6}
numeros3 := make([]int, 5)
fmt.Println(numeros1) // []
fmt.Println(numeros2) // [1 2 3 4 5 6]
fmt.Println(numeros3) // [0 0 0 0 0]
Analicemos un poco el código anterior, en el primer caso declaramos una variable numeros1
como un slice
de elementos int
, es muy similar a como declaramos un array
en casos anteriores con la única diferencia de que no pasamos ningún valor en los corchetes, por lo que se inicializa como un slice
vacío. En el segundo caso usamos la declaración corta, pasando directamente un grupo de valores entre llaves, nuevamente es muy similar a la declaración de un array
con la ausencia de un valor entre los corchetes. Finalmente tenemos la declaración de un slice
utilizando la función make
, esta función no solo permite construir slice
pero por el momento es suficiente con entender que estamos creando un slice
de números enteros con una capacidad inicial de 10, también es posible establecer explícitamente un valor inicial para la longitud del slice
pasando otro valor numérico a la función make
.
Recorriendo Arreglos y Slices
En una publicación pasada conocimos los ciclos en Go, más específicamente el ciclo for
y sus variantes. Como en muchos lenguajes de programación los ciclos permiten recorrer los valores de un arreglo, y de un slice
en este caso, de manera bastante sencilla.
nombresArray := [5]string{"Ana", "José", "Daniel", "María", "Carlos"}
for i := 0; i < len(nombresArray); i++ {
fmt.Println(nombresArray[i])
}
// Ana
// José
// Daniel
// María
// Carlos
Nada raro, muy sencillo. Tomamos lo que ya sabemos del ciclo for
y lo combinamos con lo que acabamos de aprender de los arreglos/slices y el resultado parece bastante natural. Inicializamos la variable i
con el valor 0, comprobamos la condición, que el valor actual de i
sea menor a la longitud del arreglo, realizamos la impresión de cada valor del arreglo accediendo ellos por medio de su indice, el cual introducimos de manera dinámica gracias a la variable i
que comenzará en 0 e irá incrementándose hasta que alcance el valor de la longitud del arreglo, 10 en nuestro caso, en ese momento la condición deja de cumplirse y el ciclo termina. Sin embargo Go nos proporciona una forma aún mas sencilla para recorrer un arreglo/slice, otra variación del ciclo for
que también fue explicada con anterioridad, así que me limitaré a mostrar su uso.
nombresArray := [5]string{"Ana", "José", "Daniel", "María", "Carlos"}
for i, v := range nombresArray {
fmt.Printf("Indice %d valor %s\n", i, v)
}
// Indice 0 valor Ana
// Indice 1 valor José
// Indice 2 valor Daniel
// Indice 3 valor María
// Indice 4 valor Carlos
Esta variación del ciclo for
que me gusta llamar for-range, es muy parecida a lo que se conoce como foreach
en otros lenguajes de programación. El resultado es el mismo, prácticamente, pero no requiere conocer explícitamente la longitud el arreglo, el ciclo comenzará en el indice 0 del arreglo y lo recorrerá hasta el final. Otro detalle importante es que el range
retorna dos valores, el primero es el indice y el segundo el valor.
Publicaciones relacionadas
Gracias por leer, espero que este articulo te resultara de provecho. Si así fue, no dudes en dejar un comentario, compartirlo y votar. Te invito a comentar cualquier duda o sugerencia, te aseguro que las leo todas. Así que, por favor, ayúdame a mejorar y continuar compartiendo contenido de calidad. Hasta la próxima.
Hello! Your post has been resteemed and upvoted by @ilovecoding because we love coding! Keep up good work! Consider upvoting this comment to support the @ilovecoding and increase your future rewards! ^_^ Steem On!
Reply !stop to disable the comment. Thanks!
Hi! Thank you. I gladly support you.
Interesante post el que nos muestras, no conocia el termino Slice en un lenguaje de programación, quiero suponer que es exclusivo de GO, si estoy equivocado hasmelo notar
¿Quieres recibir mejores recompensas en tus post de informática, tecnología o programación, ayúdanos delegando algo de SP:
1 SP, 5 SP, 10 SP
No me arriesgaría a decir que es Exclusivo del lenguaje. Pero en los lenguajes que conozco los arreglos son de tamaño variable, mientras que en Go son fijos. Por lo que incluyó los slice como un equivalente a los arreglos de tamaño dinámico en otros lenguajes. Quizás sea la costumbre, pero ocupo más los slice.
Congratulations @orlmicron! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :
Award for the number of upvotes received
Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word
STOP
Do not miss the last post from @steemitboard:
You make some really great points.
Thank you. A pleasure to share.
Buen posteo, voy a ver si puedo sacarle provecho a lo aprendido.
Excelente, espero puedas hacerlo. Si tienes algún problema o duda, con gusto te doy una mano.
Muchas gracias al equipo de @cervantes la comunidad hispana de Steemit sigue creciendo.
Sigamos trabajando y generando contenido de calidad.