Go by Example: Slices

Los Slices son un tipo de dato importante en Go, ofreciendo una interfaz más poderosa para secuencias que los arrays.

package main
import (
    "fmt"
    "slices"
)
func main() {

A diferencia de los arrays, los slices solo se tipan por los elementos que contienen (no por el número de elementos). Un slice no inicializado es igual a null y tiene longitud 0.

    var s []string
    fmt.Println("uninit:", s, s == nil, len(s) == 0)

Para crear un slice vacío con longitud no cero, usa la función incorporada make. Aquí hacemos un slice de strings de longitud 3 (inicialmente con valor cero). Por defecto, la capacidad de un nuevo slice es igual a su longitud; si sabemos que el slice va a crecer con el tiempo, es posible pasar una capacidad explícitamente como un parámetro adicional a make.

    s = make([]string, 3)
    fmt.Println("emp:", s, "len:", len(s), "cap:", cap(s))

Podemos configurar y obtener lo mismo que con las matrices (arrays).

    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("set:", s)
    fmt.Println("get:", s[2])

len devuelve la longitud del slice.

    fmt.Println("len:", len(s))

Además de estas operaciones básicas, los slices soportan varias más que los hacen más ricos que los arrays. Una de ellas es la función incorporada append, que devuelve un slice que contiene uno o más valores nuevos. Ten en cuenta que necesitamos aceptar un valor de retorno de append ya que podríamos obtener un nuevo valor de slice.

    s = append(s, "d")
    s = append(s, "e", "f")
    fmt.Println("apd:", s)

Los slices también pueden ser copiados con copy. Aquí creamos un slice vacío c de la misma longitud que s y copiamos en c desde s.

    c := make([]string, len(s))
    copy(c, s)
    fmt.Println("cpy:", c)

Los slices soportan un operador de "slice" con la sintaxis slice[inicio:fin]. Por ejemplo, esto obtiene un slice de los elementos s[2], s[3] y s[4].

    l := s[2:5]
    fmt.Println("sl1:", l)

Esto corta hasta (pero excluyendo) s[5].

    l = s[:5]
    fmt.Println("sl2:", l)

Y esto corta desde (e incluyendo) s[2].

    l = s[2:]
    fmt.Println("sl3:", l)

También podemos declarar e inicializar una variable para un slice en una sola línea.

    t := []string{"g", "h", "i"}
    fmt.Println("dcl:", t)

El paquete slices contiene un número de funciones utilitarias útiles para los slices.

    t2 := []string{"g", "h", "i"}
    if slices.Equal(t, t2) {
        fmt.Println("t == t2")
    }

Los slices pueden componerse en estructuras de datos multidimensionales. La longitud de los slices internos puede variar, a diferencia de los arrays multidimensionales.

    twoD := make([][]int, 3)
    for i := 0; i < 3; i++ {
        innerLen := i + 1
        twoD[i] = make([]int, innerLen)
        for j := 0; j < innerLen; j++ {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d: ", twoD)
}

Ten en cuenta que, aunque los slices son de tipos diferentes a los arrays, son representados de manera similar por fmt.Println.

$ go run slices.go
uninit: [] true true
emp: [  ] len: 3 cap: 3
set: [a b c]
get: c
len: 3
apd: [a b c d e f]
cpy: [a b c d e f]
sl1: [c d e]
sl2: [a b c d e]
sl3: [c d e f]
dcl: [g h i]
t == t2
2d:  [[0] [1 2] [2 3 4]]

Revisa este excelente artículo de blog del equipo de Go para más detalles sobre el diseño y implementación de slices en Go.

Ahora que hemos visto arrays y slices, vamos a ver otra estructura de datos incorporada clave en Go: los maps.

Siguiente ejemplo: Maps.