if con Inicialización y Patrones de switch
Go refina el código condicional al permitir que if y switch ejecuten una sentencia de inicialización de un solo uso antes de la rama, y al ofrecer switches de valor y switches de tipo en interfaces.
Busca en todas las páginas de la documentación
Go refina el código condicional al permitir que if y switch ejecuten una sentencia de inicialización de un solo uso antes de la rama, y al ofrecer switches de valor y switches de tipo en interfaces.
Dominar estas formas mantiene el manejo de errores plano y reemplaza largas cadenas if/else con una discriminación más clara.
Una sentencia de inicialización en if o switch declara variables temporales para el ámbito del bloque.
Los switches de expresión comparan un valor contra casos sin fallthrough implícito.
Los switches sin etiqueta encadenan casos booleanos como else if.
Los switches de tipo inspeccionan tipos dinámicos dentro de interfaces.
fallthrough es explícito y poco común.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
package main
import (
"fmt"
"os"
)
func main() {
// Si ocurre un error al abrir el archivo, imprímelo y sal.
// De lo contrario, cierra el archivo al final de la función.
if f, err := os.Open("config.txt"); err != nil {
fmt.Println(err)
return
} else {
defer f.Close()
fmt.Println("abierto", f.Name())
}
// Switch de valor para manejar diferentes códigos de estado.
code := 404
switch code {
case 200:
fmt.Println("ok")
case 404:
fmt.Println("no encontrado")
default:
fmt.Println("otro")
}
}Cuándo usar esto:
if err := ...; err != nil inmediatamente después de llamadas que devuelven errores.switch de valor cuando compares una expresión con muchas constantes.switch sin etiqueta con true (o condiciones desnudas) para casos booleanos ordenados.switch de tipo cuando el comportamiento dependa del tipo concreto dentro de una interface{} o una restricción genérica.package main
import (
"encoding/json"
"fmt"
)
// Event representa un evento con un tipo y una carga útil.
type Event struct {
Kind string
Payload any
}
// handle procesa un evento basándose en el tipo de su carga útil.
func handle(e Event) error {
// Type switch para determinar el tipo de Payload.
switch p := e.Payload.(type) {
case nil:
// Maneja el caso de una carga útil nula.
return fmt.Errorf("carga útil faltante para %s", e.Kind)
case json.RawMessage:
// Si la carga útil es un mensaje JSON crudo, imprime su longitud.
fmt.Println("bytes json crudos", len(p))
case map[string]any:
// Si la carga útil es un mapa, imprime el número de claves.
fmt.Println("claves de objeto", len(p))
case string:
// Si la carga útil es una cadena, imprímela.
fmt.Println("cadena", p)
default:
// Maneja tipos de carga útil no soportados.
return fmt.Errorf("carga útil no soportada %T", p)
}
return nil
}
// classify asigna una letra de calificación basada en una puntuación.
func classify(score int) string {
// Tagless switch para encadenar condiciones booleanas.
switch {
case score >= 90:
return "A"
case score >= 80:
return "B"
default:
return "C"
}
}
func main() {
events := []Event{
{Kind: "text", Payload: "hola"},
{Kind: "obj", Payload: map[string]any{"k": 1}},
}
// Itera sobre los eventos y maneja cada uno.
for _, e := range events {
// Usa if init para manejar errores inmediatamente.
if err := handle(e); err != nil {
fmt.Println(err)
}
}
// Clasifica una puntuación y imprime el resultado.
fmt.Println(classify(85))
}Lo que esto demuestra:
p := e.Payload.(type) vincula una variable tipada por cada caso.default maneja tipos dinámicos inesperados con %T en los errores.switch sin expresión de etiqueta encadena comparaciones como if/else if.if/switch.fallthrough.switch puede incluir una sentencia de inicialización: switch err := f(); err != nil { case ... } (poco común pero válido).| Forma | Sintaxis | Coincide en |
|---|---|---|
| Valor | switch x { case v: | igualdad en x comparable |
| Sin etiqueta | switch { case cond: | booleano cond |
| Tipo | switch v := i.(type) { case T: | tipo dinámico de la interfaz i |
| Con inicialización | switch x := f(); x { | valor de x después de la inicialización |
| Regla | Comportamiento |
|---|---|
| Predeterminado | Detenerse después del primer caso coincidente |
fallthrough | Continuar al siguiente caso incondicionalmente |
| Último caso | Se permite fallthrough a default pero es raro |
// Comprobación de tipo con coma-ok en if - alternativa al type switch para un solo tipo
if s, ok := v.(string); ok {
fmt.Println(s)
}
// Los switch en strings con casos duplicados son un error de compilación
// Coincidencia insensible a mayúsculas/minúsculas: normaliza antes del switch o usa un switch sin etiquetaerr después del bloque if cuando se declara en la inicialización. Solución: mantén el manejo dentro del bloque o declara err fuera intencionalmente.break (errores de C) no aplica, pero un fallthrough accidental causa doble ejecución. Solución: elimina fallthrough a menos que sea deliberado.x.(type) solo funciona en operandos de interfaz. Solución: pasa any o un pequeño envoltorio de interfaz.switch v := i.(type) { case *T: } puede coincidir con un puntero nulo tipado. Solución: comprueba v == nil dentro del caso.case 1, 2:.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
Cadena if/else | Pocas ramas con condiciones no relacionadas | Muchas constantes sobre un valor |
Búsqueda en mapa handlers[key] | Tabla de despacho para cadenas | Necesidad de comprobaciones de exhaustividad en compilación |
Asignación de tipo v.(T) | Un solo tipo conocido | Muchos tipos para discriminar |
| Genéricos + restricciones | Conjuntos de tipos en tiempo de compilación | Blobs JSON heterogéneos en tiempo de ejecución |
errors.Is / errors.As | Inspección de cadena de errores | Valores de interfaz que no son de error |
Mantiene la variable de error dentro del ámbito de la comprobación.
Los lectores ven la adquisición y la validación juntas.
Casi nunca en código de aplicación.
Prefiere llamadas a funciones auxiliares compartidas desde múltiples casos en su lugar.
Los casos deben ser constantes comparables en tiempo de compilación o expresiones booleanas (forma sin etiqueta).
No puedes hacer switch directamente sobre un slice - usa patrones de índice o longitud en su lugar.
Los type switches manejan muchos tipos en una sola construcción.
La asignación de tipo v.(T) apunta a un solo tipo y devuelve ok.
Para interfaces, el valor dinámico puede copiarse dependiendo del tipo.
Valores grandes - usa switch sobre un puntero o índice en su lugar.
Sí - compara con errors.Is en casos sin etiqueta:
case errors.Is(err, os.ErrNotExist):
Una forma más antigua de switch sin etiqueta.
switch { case cond: es la forma moderna idiomática.
Sí - if a, err := f(); err != nil funciona como una declaración de variable corta.
Al menos un nombre debe ser nuevo en algunos contextos con las reglas de reutilización de :=.
Sí, pero son inútiles - usualmente una señal para eliminar o añadir manejo.
Los linters pueden marcar casos vacíos.
Trata las runes como enteros con constantes de caracteres:
case '+', '-':
if y switchifif estilo inicializaciónVersiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado GC de Green Tea, go fix modernizers - verificar parche en la compilación), chi (última - verificar en la compilación), gin (última - verificar en la compilación), echo (última - verificar en la compilación), google.golang.org/grpc (última - verificar en la compilación), sigs.k8s.io/controller-runtime (última - verificar en la compilación), kubebuilder (última - verificar en la compilación), tinygo (última - verificar objetivos de placa en la compilación), wazero (última - verificar en la compilación), y golangci-lint (última - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026