Flujo de control con instrucciones switch
Al igual que otros lenguajes de programación, Go admite instrucciones switch
. Las instrucciones switch
se usan para evitar encadenar varias instrucciones if
. Mediante las instrucciones switch
, se evita la dificultad de mantener y leer código que incluye muchas instrucciones if
. Estas instrucciones también facilitan la construcción de condiciones complicadas. Eche un vistazo a las instrucciones switch
de las secciones siguientes.
Sintaxis básica de switch
Al igual que la instrucción if
, la condición switch
no necesita paréntesis. En su forma más simple, una instrucción switch
tiene el siguiente aspecto:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
sec := time.Now().Unix()
rand.Seed(sec)
i := rand.Int31n(10)
switch i {
case 0:
fmt.Print("zero...")
case 1:
fmt.Print("one...")
case 2:
fmt.Print("two...")
}
fmt.Println("ok")
}
Si ejecuta el código anterior varias veces, verá una salida diferente cada vez. (Sin embargo, si ejecuta el código en el área de juegos de Go, obtendrá siempre el mismo resultado. Esa es una de las limitantes del servicio).
Go compara cada caso de la instrucción switch
hasta que encuentra una coincidencia para la condición. Observe, sin embargo, que el código anterior no cubre todos los casos posibles de los valores de la variable num
. Si num
termina siendo 5
, la salida del programa es ok
.
También puede ser más específico sobre el caso de uso predeterminado e incluirlo de la siguiente manera:
switch i {
case 0:
fmt.Print("zero...")
case 1:
fmt.Print("one...")
case 2:
fmt.Print("two...")
default:
fmt.Print("no match...")
}
Observe que, en el caso de default
, no escribe una expresión de validación. El valor de la variable i
se valida con las instrucciones case
y el caso default
controla los valores no validados.
Uso de varias expresiones
En ocasiones, más de una expresión coincide con una sola instrucción case
. En Go, si quiere que una instrucción case
incluya más de una expresión, separe las expresiones mediante comas (,
). Esta técnica impide que se duplique el código.
En el ejemplo de código siguiente se muestra cómo incluir varias expresiones.
package main
import "fmt"
func location(city string) (string, string) {
var region string
var continent string
switch city {
case "Delhi", "Hyderabad", "Mumbai", "Chennai", "Kochi":
region, continent = "India", "Asia"
case "Lafayette", "Louisville", "Boulder":
region, continent = "Colorado", "USA"
case "Irvine", "Los Angeles", "San Diego":
region, continent = "California", "USA"
default:
region, continent = "Unknown", "Unknown"
}
return region, continent
}
func main() {
region, continent := location("Irvine")
fmt.Printf("John works in %s, %s\n", region, continent)
}
Observe que los valores que se incluyen en las expresiones para la instrucción case
corresponden al tipo de datos de la variable que valida la instrucción switch
. Si incluye un valor entero como una nueva instrucción case
, el programa no se compilará.
Invocar una función
Una instrucción switch
también puede invocar una función. Desde esa función, puede escribir instrucciones case
para los posibles valores devueltos. Por ejemplo, el código siguiente llama a la función time.Now()
. La salida que imprime depende del día de la semana actual.
package main
import (
"fmt"
"time"
)
func main() {
switch time.Now().Weekday().String() {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
fmt.Println("It's time to learn some Go.")
default:
fmt.Println("It's the weekend, time to rest!")
}
fmt.Println(time.Now().Weekday().String())
}
Cuando se llama a una función desde una instrucción switch
, puede modificar su lógica sin cambiar la expresión porque siempre se valida lo que devuelve la función.
Además, puede llamar a una función desde una instrucción case
. Utilice esta técnica, por ejemplo, para buscar coincidencias con un patrón determinado mediante una expresión regular. Este es un ejemplo:
package main
import "fmt"
import "regexp"
func main() {
var email = regexp.MustCompile(`^[^@]+@[^@.]+\.[^@.]+`)
var phone = regexp.MustCompile(`^[(]?[0-9][0-9][0-9][). \-]*[0-9][0-9][0-9][.\-]?[0-9][0-9][0-9][0-9]`)
contact := "foo@bar.com"
switch {
case email.MatchString(contact):
fmt.Println(contact, "is an email")
case phone.MatchString(contact):
fmt.Println(contact, "is a phone number")
default:
fmt.Println(contact, "is not recognized")
}
}
Observe que el bloque switch
no tiene ninguna expresión de validación. En la próxima sección, hablaremos sobre ese concepto.
Omisión de una condición
En Go, puede omitir una condición en una instrucción switch
igual que hace en una instrucción if
. Este patrón es parecido a comparar un valor true
como si estuviera obligando a que la instrucción switch
se ejecutara todo el tiempo.
Este es un ejemplo de cómo escribir una instrucción switch
sin una condición:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().Unix())
r := rand.Float64()
switch {
case r > 0.1:
fmt.Println("Common case, 90% of the time")
default:
fmt.Println("10% of the time")
}
}
El programa siempre ejecuta este tipo de instrucción switch
porque la condición siempre es true. Un bloque switch
condicional puede ser más fácil de mantener que una cadena larga de instrucciones if
y else if
.
Hacer que la lógica lleve al siguiente caso
En algunos lenguajes de programación, se escribe una palabra clave break
al final de cada instrucción case
. Sin embargo, en Go, cuando la lógica pertenece a un caso, sale del bloque switch
a menos que se detenga explícitamente. Para que la lógica lleve al siguiente caso inmediato, use la palabra clave fallthrough
.
Para comprender mejor este patrón, examine el siguiente ejemplo de código.
package main
import (
"fmt"
)
func main() {
switch num := 15; {
case num < 50:
fmt.Printf("%d is less than 50\n", num)
fallthrough
case num > 100:
fmt.Printf("%d is greater than 100\n", num)
fallthrough
case num < 200:
fmt.Printf("%d is less than 200", num)
}
}
Ejecute el código y analice la salida:
15 is less than 50
15 is greater than 100
15 is less than 200
¿Ve que algo esté mal?
Tenga en cuenta que, como num
es 15 (menor que 50), coincide con el primer caso. Sin embargo, num
no es mayor que 100. Y, como la primera instrucción case
tiene una palabra clave fallthrough
, la lógica lleva inmediatamente a la siguiente instrucción case
sin validar el caso. Por lo tanto, debe tener cuidado al usar la palabra clave fallthrough
. Puede que no desee el comportamiento que crea este código.