Introducción: ¿Por qué los programadores de Python extrañan "in" en Go?
\n\nSi llegaste a Go desde el mundo de Python, seguramente recuerdas esa línea mágica: if "banana" in fruits:. Corta, elegante, legible. Y luego abres Go y te preguntas: "Does Go have 'if x in' construct similar to Python?" — así suena la pregunta más popular en Stack Overflow, que ha acumulado miles de visitas.
Advertencia: no hay azúcar sintáctico directo como in en Go. Pero eso no significa que la tarea no tenga solución o sea difícil de resolver. Al contrario, en Go existen varias formas idiomáticas de verificar pertenencia, cada una eficiente y elegante a su manera.
En este artículo analizaremos:
\n- \n
- Por qué no hay
inen Go y cómo la filosofía del lenguaje influyó en esto; \n - Cómo verificar la presencia de un elemento en un slice (incluyendo el uso de la nueva función
slices.Contains); \n - Cómo funciona la búsqueda en un mapa (spoiler: es la forma más rápida); \n
- Búsqueda de subcadenas en una cadena mediante
strings.Contains; \n - Escribiremos nuestra propia función envolvente universal para un estilo "pitónico"; \n
- Compararemos el rendimiento de los enfoques. \n
¿Por qué Go no quiere "if x in"?
\n\nGo es un lenguaje minimalista. Sus creadores (Rob Pike, Ken Thompson, Rob Griesemer) evitaron conscientemente sobrecargar la sintaxis. En lugar de agregar la palabra clave in, propusieron usar bucles explícitos y construcciones integradas.
Esto no es una deficiencia, sino una característica: siempre ves exactamente lo que está sucediendo. Por ejemplo, para un mapa, la sintaxis value, ok := myMap[key] te da no solo la verificación de presencia, sino también el valor en sí; esto es más potente que un simple booleano True/False.
Método 1: Búsqueda en un slice (clásico)
\n\nEl escenario más común. Supongamos que tienes un slice de cadenas y necesitas verificar si "Go" está allí.
\n\nHasta la versión Go 1.21, tenías que escribir el bucle manualmente:
\n\npackage main\n\nimport "fmt"\n\nfunc contains(slice []string, target string) bool {\n for _, v := range slice {\n if v == target {\n return true\n }\n }\n return false\n}\n\nfunc main() {\n languages := []string{"Python", "Java", "Go", "Rust"}\n if contains(languages, "Go") {\n fmt.Println("¡Go encontrado!")\n }\n}\n\n\nEste código es Go idiomático. Es explícito, rápido y comprensible. Para slices pequeños (hasta 1000 elementos), esta búsqueda lineal funciona perfectamente.
\n\nMétodo 1.1: Usando slices.Contains (Go 1.21+)
\n\nA partir de la versión Go 1.21 (lanzada en agosto de 2023), la biblioteca estándar incluye el paquete slices con la función lista Contains. Ahora tu código se vuelve casi tan conciso como en Python:
package main\n\nimport (\n "fmt"\n "slices"\n)\n\nfunc main() {\n languages := []string{"Python", "Java", "Go", "Rust"}\n if slices.Contains(languages, "Go") {\n fmt.Println("¡Go encontrado! (a través de slices.Contains)")\n }\n}\n\n\nImportante: slices.Contains es una función genérica. Funciona con cualquier tipo que admita el operador == (cadenas, números, valores booleanos, estructuras sin slices/mapas internos).
Método 2: Búsqueda en un mapa — el rey del rendimiento
\n\nEn Python usas in para diccionarios, y esto es tiempo constante O(1). En Go es lo mismo, pero la sintaxis es diferente:
package main\n\nimport "fmt"\n\nfunc main() {\n // Creamos un mapa como set\n fruits := map[string]bool{\n "apple": true,\n "banana": true,\n "cherry": true,\n }\n\n if fruits["banana"] {\n fmt.Println("¡banana está!")\n }\n\n // Forma más correcta — con verificación ok\n if _, ok := fruits["orange"]; ok