Break, que desconcierta: cómo Go revolucionó la «regla habitual del switch»
\n\nSi alguna vez has programado en C, C++, Java o JavaScript, conoces el ritual: después de cada case en un switch hay que poner un break. De lo contrario, bienvenido al infierno del «fall-through», donde el código se ejecuta de un case a otro hasta que encuentra un break o el final de la estructura.
Ahora imagina: te pasas a Go, escribes un switch y por costumbre pones un break al final de cada case. El código funciona. Pero te preguntas: «¿Realmente es necesario? ¿Y qué pasaría si lo quito?».
Esta pregunta es una de las más populares en Stack Overflow en la sección de Go. Y la respuesta sorprende a los principiantes: en Go, break en switch y select no es obligatorio, pero existe y hace algo diferente. Analicémoslo con ejemplos para que nunca más te confundas.
\n\nGo vs. C: el switch «invertido»
\n\nEn los lenguajes clásicos tipo C, switch funciona así:
// Pseudocódigo C\nint x = 2;\nswitch(x) {\n case 1:\n printf("Uno");\n break; // Sin break — pasa al siguiente case\n case 2:\n printf("Dos");\n break;\n default:\n printf("Otro");\n}\n// Salida: "Dos"\n\nSi quitas el break después de case 1, el programa imprimirá «UnoDos». Este comportamiento se llama fall-through y a menudo provoca errores.
En Go decidieron: «¡Basta ya!» Por defecto, cada case en switch termina automáticamente y no necesita break:
package main\n\nimport "fmt"\n\nfunc main() {\n x := 2\n switch x {\n case 1:\n fmt.Println("Uno")\n // break no es necesario — salimos del switch\n case 2:\n fmt.Println("Dos")\n // break no es necesario\n default:\n fmt.Println("Otro")\n }\n // Salida: "Dos"\n}\n\nPero si igual pones un break — no pasa nada, el código simplemente sale del switch antes. Sin embargo, ¿para qué poner un break extra si ese es el comportamiento por defecto?.
¿Y el fall-through?
\n\nSi necesitas «caer» al siguiente case, Go ofrece una palabra clave explícita: fallthrough:
switch x {\ncase 1:\n fmt.Println("Uno")\n fallthrough // Decimos explícitamente: «Quiero ir al siguiente case»\ncase 2:\n fmt.Println("Dos")\ndefault:\n fmt.Println("Otro")\n}\n// Con x=1 imprimirá: "Uno" y "Dos"\n\nNota: fallthrough solo funciona para el siguiente case y no en cadena. Esto se hizo a propósito para evitar errores accidentales.
Select: el «hermano» multicanal de switch
\n\nGo tiene una construcción única: select. Es similar a switch, pero solo funciona con canales. Y aquí también existe break, pero con un truco.
package main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc main() {\n ch1 := make(chan string)\n ch2 := make(chan string)\n\n go func() {\n time.Sleep(1 * time.Second)\n ch1 <- "Hola desde el canal 1"\n }()\n go func() {\n time.Sleep(2 * time.Second)\n ch2 <- "Hola desde el canal 2"\n }()\n\n select {\n case msg1 := <-ch1:\n fmt.Println(msg1)\n break // Salida de select\n case msg2 := <-ch2:\n fmt.Println(msg2)\n break // Salida de select\n case <-time.After(3 * time.Second):\n fmt.Println("Tiempo de espera agotado")\n }\n}\n\nAquí break tampoco es obligatorio — select termina después de ejecutar un case. Pero ¿para qué sirve?. La respuesta: ¡para salir de un bucle externo!