control-flujo-if-else-scope

Condicionales if y else en Go con alcance de variables

  • 4 min

Un condicional if en Go es una estructura que ejecuta código solo si se cumple una condición. Es la forma más directa de hacer que un programa tome decisiones.

Cualquier programa que haga algo útil necesita tomar decisiones. “Si pasa esto, haz aquello; si no, haz lo otro”.

Vamos a ver cómo Go maneja las sentencias condicionales. Si vienes de C, Java o C#, la sintaxis te resultará familiar, aunque hay diferencias en los paréntesis y en el ámbito de las variables.

La sentencia if básica

La estructura básica es casi idéntica a la mayoría de lenguajes derivados de C, pero con dos reglas de oro:

  1. No se usan paréntesis rodeando la condición.
  2. Las llaves { } son OBLIGATORIAS, incluso si solo hay una línea de código dentro.
package main

import "fmt"

func main() {
    edad := 18

    // Fíjate: sin paréntesis en la condición
    if edad >= 18 {
        fmt.Println("Eres mayor de edad")
    }
}
Copied!

Si pones paréntesis if (edad >= 18), el compilador no se quejará, pero la herramienta de formateo oficial gofmt los eliminará automáticamente al guardar. Go quiere un estilo único y limpio.

else y else if

Podemos encadenar condiciones lógicamente. Aquí hay una regla de formateo estricta: la palabra clave else debe estar en la misma línea que la llave de cierre } del bloque anterior.

Si pones el else en una línea nueva, Go (que inserta puntos y coma automáticamente al final de las líneas) pensará que el if ha terminado y te dará un error de compilación.

func main() {
    puntuacion := 75

    if puntuacion >= 90 {
        fmt.Println("Sobresaliente")
    } else if puntuacion >= 70 { // Correcto: else en la misma línea que }
        fmt.Println("Notable")
    } else {
        fmt.Println("Aprobado")
    }
}
Copied!

Incorrecto (Error de sintaxis):

if puntuacion > 90 {
    ...
}
else { // ERROR: syntax error: unexpected else, expecting }
    ...
}
Copied!

Declarar variables dentro del if

Una diferencia interesante respecto a C# o Java es que el if en Go puede aceptar una sentencia corta de inicialización antes de la condición, separada por un punto y coma ;.

Sintaxis: if variable := valor; condicion { ... }

Esto es increíblemente útil para ejecutar una función, guardar su resultado, comprobarlo y limitar la vida de esa variable únicamente al bloque condicional.

Ejemplo clásico

Imagina que queremos obtener un valor de una función y comprobar si es válido.

Forma tradicional (Variable “ensucia” el scope externo):

func main() {
    usuario := obtenerUsuario() // La variable 'usuario' vive en todo el main

    if usuario == "Luis" {
        fmt.Println("Acceso concedido")
    }

    // Aquí 'usuario' sigue estando disponible, aunque ya no lo necesitamos.
}
Copied!

Forma idiomática en Go (Scope limitado):

func main() {
    // Definimos 'usuario' DENTRO del encabezado del if
    if usuario := obtenerUsuario(); usuario == "Luis" {
        fmt.Println("Acceso concedido a", usuario)
    } else {
        // 'usuario' también es accesible en el bloque else
        fmt.Println("Acceso denegado a", usuario)
    }

    // Aquí 'usuario' YA NO EXISTE.
    // fmt.Println(usuario) // Esto daría error de compilación
}
Copied!

¿Por qué esto es tan importante?

Esta característica aparece constantemente en el manejo de errores en Go (que veremos más adelante). Un patrón muy habitual es:

// Intentamos hacer algo que puede fallar
if err := hacerAlgo(); err != nil {
    // Si hubo error, lo manejamos aquí
    log.Fatal(err)
}
// Aquí 'err' ya no existe, el scope está limpio
Copied!

Ámbito de las variables

Entender el scope es importante para evitar shadowing (ocultar variables) y bugs lógicos.

  1. Variables declaradas antes del if: son visibles dentro y fuera del bloque.
  2. Variables declaradas en la inicialización: son visibles dentro del bloque if y de los bloques else if y else encadenados. No existen fuera.
package main

import "fmt"

func main() {
    x := 10 // Visible en todo main

    if x > 5 {
        y := 5 // Variable local del bloque if
        fmt.Println(x, y) // Funciona
    }

    // fmt.Println(y) // ERROR: undefined: y

    // Ejemplo de shadowing (CUIDADO)
    if x := 100; x > 10 {
        fmt.Println(x) // Imprime 100 (la x local del if oculta a la x externa)
    }

    fmt.Println(x) // Imprime 10 (la x externa no fue modificada)
}
Copied!

Ten cuidado con usar := si tu intención es modificar una variable externa. Si usas := dentro del if con el mismo nombre, crearás una nueva variable local en lugar de actualizar la de fuera.