Contains en Go para slices: cómo verificar y no volverse loco

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

«¿Y dónde está contains?» — el primer dolor del novato en Go

\n\n

Imagínese: está programando en Go, tiene un slice de strings ["python", "go", "rust", "javascript"] y necesita verificar si el lenguaje "go" está presente. Si viene de Python, Ruby o JavaScript, automáticamente escribe slice.contains("go") — y obtiene un error de compilación en rojo. «¿Qué tontería es esta?» — piensa. «¡En cualquier colección que se respete hay un método contains!»

\n\n

Tranquilidad, solo tranquilidad. En Go realmente no hay un método contains incorporado para slices. Y esto no es un error, sino una característica. Los desarrolladores del lenguaje decidieron que una función universal no cubriría todos los casos (comparación de strings, números, estructuras) y dejaron la implementación al programador. Suena aterrador, pero en realidad es simple y elegante. En este artículo analizaremos cómo escribir contains para un slice en Go, veremos el rendimiento, los errores típicos y mostraremos soluciones listas.

\n\n

¿Por qué no hay contains para slices en Go?

\n

Go es un lenguaje minimalista. No tiene genéricos (hasta la versión 1.18) ni sobrecarga de métodos. Un slice no es un objeto con métodos, sino una estructura de datos: un puntero a un array, longitud y capacidad. Los desarrolladores de Go decidieron que la función contains debe ser explícita, para que el programador siempre entienda cómo ocurre la comparación. Esto reduce la cantidad de errores y hace que el código sea predecible.

\n

Además, contains para un slice siempre es una búsqueda lineal (O(n)), y si espera O(1), está usando la estructura incorrecta (necesita un map). Go no quiere ocultar esta complejidad.

\n\n

El contains más simple para un slice en Go (recorrido manual)

\n

Escribamos contains para un slice de strings. Esto es un clásico que verá en cualquier código de producción:

\n\n
package main\n\nimport "fmt"\n\n// Contains verifica si un elemento está en el slice de strings\nfunc Contains(slice []string, target string) bool {\n    for _, item := range slice {\n        if item == target {\n            return true\n        }\n    }\n    return false\n}\n\nfunc main() {\n    languages := []string{"python", "go", "rust", "javascript"}\n    fmt.Println(Contains(languages, "go"))       // true\n    fmt.Println(Contains(languages, "csharp"))   // false\n}
\n\n

Muy simple: recorremos el slice con un bucle, comparamos cada elemento con el buscado. Si lo encontramos — true, si no — false. Importante: el operador == funciona para strings, números, valores booleanos y punteros. Para estructuras o slices dentro de slices (anidados) no funcionará así.

\n\n

Contains para números

\n

Para un slice de números enteros, el código es casi idéntico:

\n\n
func ContainsInt(slice []int, target int) bool {\n    for _, v := range slice {\n        if v == target {\n            return true\n        }\n    }\n    return false\n}\n\nfunc main() {\n    numbers := []int{10, 20, 30, 40, 50}\n    fmt.Println(ContainsInt(numbers, 30)) // true\n    fmt.Println(ContainsInt(numbers, 99)) // false\n}
\n\n

¿Incómodo? Sí. Pero esto es Go: la claridad y la simplicidad están por encima de todo.

\n\n

Contains universal para un slice en Go (genéricos, Go 1.18+)

\n

Con el lanzamiento de Go 1.18, el lenguaje incorporó los genéricos (generalizaciones). Ahora se puede escribir una única función contains para cualquier tipo que soporte comparación:

\n\n
package main\n\nimport "fmt"\n\n// ContainsGeneric funciona para cualquier tipo comparable\nfunc ContainsGeneric[T comparable](slice []T, target T) bool {\n    for _, item := range slice {\n        if item == target {\n            return true\n        }\n    }\n    return false\n}\n\nfunc main() {\n    strs := []string{"a", "b", "c"}\n    ints := []int{1, 2, 3}\n    floats := []float64{1.1, 2.2, 3.3}\n\n    fmt.Println(ContainsGeneric(strs, "b"))   // true\n    fmt.Println(ContainsGeneric(ints, 5))     // false\n    fmt.Println(ContainsGeneric(floats, 2.2)) // true\n}
\n\n

La restricción comparable significa que el tipo soporta los operadores == y

Blogs

Book Recommendations