# Go desde Cero, Pero Bien: Funciones y Control de Flujo

Go desde Cero, Pero Bien: Funciones y Control de Flujo
Tabla de Contenidos

🧩 Módulo 1, Capítulo 3: Funciones y Control de Flujo- Los Bloques de Construcción de tu Código

Muchachones hasta ahora, hemos visto cómo se organiza un programa Go (package main, func main) y cómo manejamos datos (variables, arrays, slices) y errores. Pero, cómo organizamos la lógica de nuestro programa para que sea modular, reutilizable y fácil de entender??? La respuesta son las funciones.

Una función es un bloque de código independiente que realiza una tarea específica. En Go, las funciones son ciudadanas de primera clase, lo que significa que pueden ser asignadas a variables, pasadas como argumentos y devueltas por otras funciones.

Declarando una Función: La Firma

Cada función en Go tiene una firma bien definida que especifica su nombre, los parámetros que recibe y los valores que devuelve.

package main
import "fmt"
// Una función simple que no toma parámetros y no devuelve nada.
func saludar() {
fmt.Println("Hola cesarlead!!! desde una función!!!")
}
// Una función que toma un parámetro y no devuelve nada.
func saludarNombre(nombre string) {
fmt.Printf("¡Hola, %s!\n", nombre)
}
// Una función que toma un parámetro y devuelve un valor.
func sumar(a int, b int) int {
resultado := a + b
return resultado
}
// Go permite agrupar parámetros del mismo tipo.
func restar(a, b int) int {
return a - b
}
func main() {
saludar() // Llamando a la función sin parámetros
saludarNombre("Mundo") // Llamando a la función con un parámetro
suma := sumar(5, 3) // Llamando a la función que devuelve un valor
fmt.Println("La suma es:", suma)
diferencia := restar(10, 4)
fmt.Println("La diferencia es:", diferencia)
}

Anatomía de una Firma de Función:

  • func: La palabra clave que indica que estás declarando una función.

  • nombreDeLaFuncion: El identificador de la función. En Go, las funciones que empiezan con mayúscula son * exportadas* (visibles fuera del paquete), y las que empiezan con minúscula son no exportadas (solo visibles dentro del paquete).

  • Parámetros (param1 tipo1, param2 tipo2, ...): Una lista de variables que la función espera recibir. Cada parámetro tiene un nombre y un tipo. Si varios parámetros consecutivos son del mismo tipo, puedes agruparlos como en (a, b int).

  • Valores de Retorno (tipoRetorno1, tipoRetorno2, ...): Una lista de los tipos de datos que la función devolverá. Go permite que una función devuelva múltiples valores, lo cual es una característica muy poderosa (como vimos con el tipo error). Si solo devuelve un valor, los paréntesis son opcionales. Si no devuelve nada, se omite por completo.

Análisis Quirúrgico: Cómo se llama una función?

Cuando llamas a una función, el flujo de ejecución de tu programa salta al inicio de esa función. Go crea un nuevo * marco de pila (stack frame)* para esa llamada. En este marco de pila se almacenan:

  1. Los argumentos pasados a la función.

  2. Las variables locales declaradas dentro de la función.

  3. La dirección de retorno, que le dice a Go dónde continuar la ejecución una vez que la función termina.

Cuando la función ejecuta un return, los valores de retorno son colocados en la pila (o registros de CPU), y el control salta de vuelta a la dirección de retorno en el código que la llamó. El marco de pila de la función llamada se ” desapila” y su memoria es marcada como disponible.

Funciones con Múltiples Valores de Retorno

Mis bros, como ya vimos con el tipo error, esta es una de las características más distintivas y útiles de Go. Permite a las funciones devolver su resultado normal junto con información adicional, como un estado de éxito/fallo.

package main
import (
"errors"
"fmt"
)
// Esta función devuelve un entero y un error.
func dividirConValidacion(dividendo int, divisor int) (int, error) {
if divisor == 0 {
// Devolvemos 0 como resultado y un nuevo error.
return 0, errors.New("no se puede dividir por cero")
}
// Devolvemos el resultado y nil (indicando que no hubo error).
return dividendo / divisor, nil
}
func main() {
resultado, err := dividirConValidacion(10, 2)
if err != nil {
fmt.Println("Hubo un error:", err)
} else {
fmt.Println("El resultado de la división es:", resultado) // Imprime: 5
}
resultado2, err2 := dividirConValidacion(7, 0)
if err2 != nil {
fmt.Println("Hubo un error:", err2) // Imprime: Hubo un error: no se puede dividir por cero
} else {
fmt.Println("El resultado de la división es:", resultado2)
}
}

Este patrón (valor, error) es omnipresente en Go y te obliga a manejar los errores explícitamente, lo que lleva a un código más robusto.

Retornos Nombrados (Named Return Values)

Go tambien te permite nombrar los valores de retorno de una función. Cuando haces esto, estos nombres actúan como variables locales dentro de la función, inicializadas con el valor cero de su tipo. Puedes asignarles valores directamente, y un return sin argumentos al final de la función devolverá automáticamente los valores actuales de esas variables nombradas.

package main
import "fmt"
// La función 'calcularOperaciones' tiene valores de retorno nombrados: 'suma' y 'producto'.
func calcularOperaciones(a, b int) (suma int, producto int) {
suma = a + b // Asignamos directamente a la variable de retorno 'suma'.
producto = a * b // Asignamos directamente a la variable de retorno 'producto'.
return // Un 'return' vacío devuelve los valores actuales de 'suma' y 'producto'.
}
func main() {
s, p := calcularOperaciones(4, 6)
fmt.Printf("Suma: %d, Producto: %d\n", s, p) // Imprime: Suma: 10, Producto: 24
}

Uso y Consideraciones:

Los retornos nombrados pueden hacer que el código sea más legible para funciones que devuelven múltiples valores del mismo tipo o cuando los nombres de retorno aclaran el propósito de cada valor. Sin embargo, si se abusan (los extremos no son buenos), pueden hacer el flujo de la función menos obvio. Para funciones simples, un return explícito suele ser más claro.

Funciones Variádicas: Cantidad Variable de Argumentos

Una función variádica es aquella que puede aceptar un número variable de argumentos del mismo tipo. Se indica con tres puntos (...) antes del tipo del último parámetro. Dentro de la función, este parámetro se convierte en un slice del tipo especificado.

package main
import "fmt"
// `numeros ...int` significa que esta función puede tomar cero o más enteros.
func sumarTodos(numeros ...int) int {
total := 0
// `numeros` se comporta como un slice []int dentro de la función.
for _, num := range numeros {
total += num
}
return total
}
func main() {
fmt.Println("Suma de (1, 2, 3):", sumarTodos(1, 2, 3)) // Pasa argumentos individuales
fmt.Println("Suma de (10, 20):", sumarTodos(10, 20)) // Pasa menos argumentos
fmt.Println("Suma de (5):", sumarTodos(5)) // Pasa un solo argumento
fmt.Println("Suma de (ninguno):", sumarTodos()) // Pasa cero argumentos
// También puedes pasar un slice existente a una función variádica usando `...`
edades := []int{25, 30, 22, 40}
fmt.Println("Suma de edades:", sumarTodos(edades...)) // Importante el '...' aquí!!!
}

Cómo Funciona por Debajo:

Cuando llamas a una función variádica, Go internamente toma todos los argumentos adicionales que le pasas y los empaqueta en un nuevo slice. Es ese slice el que se pasa a la función. Si ya tienes un slice y quieres pasárselo a una función variádica, debes “desempaquetarlo” usando el operador ... como en sumarTodos(edades...). Esto le dice a Go que trate los elementos del slice edades como argumentos individuales para la función variádica.

Funciones Anónimas (Closures): Funciones sin Nombre

Una función anónima es, como su nombre indica, una función sin un nombre. Pueden ser declaradas directamente donde se usan. Son particularmente útiles para tareas pequeñas que no necesitan ser reutilizadas o para crear closures. Un closure es una función anónima que “captura” variables de su entorno circundante, incluso después de que ese entorno haya terminado su ejecución.

package main
import "fmt"
func main() {
// Declaración y llamada inmediata de una función anónima
func() {
fmt.Println("Soy una función anónima ejecutada al instante.")
}() // Los paréntesis aquí la ejecutan
// Asignar una función anónima a una variable
saludarAnonimo := func(nombre string) {
fmt.Printf("¡Hola %s desde una función anónima asignada!\n", nombre)
}
saludarAnonimo("Go Developer")
// Closure: La función `contador` captura la variable `i` de su entorno.
incrementador := crearIncrementador()
fmt.Println(incrementador()) // 1
fmt.Println(incrementador()) // 2
fmt.Println(incrementador()) // 3
otroIncrementador := crearIncrementador() // Otro closure, con su propia 'i'
fmt.Println(otroIncrementador()) // 1
}
// Esta función devuelve una función anónima (un closure).
func crearIncrementador() func() int {
i := 0 // Esta variable es "capturada" por la función anónima devuelta.
return func() int {
i++ // 'i' persiste entre llamadas a la función devuelta.
return i
}
}

El Poder de los Closures:

La magia del closure en crearIncrementador reside en que la variable i no se recrea cada vez que se llama a la función incrementador. En su lugar, cada vez que llamas a crearIncrementador(), se crea una nueva instancia de la variable i en la memoria, y la función anónima que se devuelve “cierra” sobre esa instancia específica de i. Por eso, incrementador y otroIncrementador tienen sus propios contadores independientes. Esto es fundamental para patrones como generadores, callbacks y gestión de estado.


Funciones como Tipos

En Go, los tipos de funciones también son tipos de datos. Esto significa que puedes declarar variables de tipo función, pasar funciones como argumentos a otras funciones (conocidas como funciones de orden superior), y devolver funciones desde otras funciones. (Todo un trabalenguas hahaha)

package main
import "fmt"
// Define un nuevo tipo de función: Operacion es una función que toma dos enteros y devuelve un entero.
type Operacion func(int, int) int
// `ejecutarOperacion` es una función de orden superior porque toma una función como argumento.
func ejecutarOperacion(op Operacion, a, b int) int {
fmt.Println("Ejecutando operación...")
return op(a, b) // Llama a la función que se le pasó como argumento
}
func main() {
// Declara una función anónima para la suma.
sumarFn := func(x, y int) int {
return x + y
}
// Declara una función anónima para la multiplicación.
multiplicarFn := func(x, y int) int {
return x * y
}
// Pasa las funciones como argumentos.
fmt.Println("Resultado de la suma:", ejecutarOperacion(sumarFn, 5, 3))
fmt.Println("Resultado de la multiplicación:", ejecutarOperacion(multiplicarFn, 5, 3))
}

Abstracción y Flexibilidad:

Al tratar las funciones como tipos, puedes escribir código más modular y flexible. Puedes crear algoritmos genéricos que operen sobre diferentes lógicas pasadas como funciones, sin tener que reescribir el algoritmo completo. Esto es la base de muchos patrones de diseño y la potencia de los concurrentes en Go (goroutines y canales).


Buenos muchachones sigamos: Tomando Decisiones con Condicionales IF / ELSE

Hasta ahora, nuestros programas han seguido un camino lineal o se han repetido usando for loops. Pero el software real necesita tomar decisiones: “si esto es verdad, haz esto; de lo contrario, haz aquello”. Aquí es donde entran en juego los condicionales.

En Go, la principal construcción para la toma de decisiones es la sentencia if.

La Sentencia if: La Decisión Básica

La forma más simple de un condicional es la sentencia if. Se utiliza para ejecutar un bloque de código solo si una condición específica es verdadera.

package main
import "fmt"
func main() {
temperatura := 25
// Si la condición (temperatura > 20) es verdadera, el bloque de código se ejecuta.
if temperatura > 20 {
fmt.Println("Hace calor hoy.")
}
edad := 17
if edad >= 18 {
fmt.Println("Eres mayor de edad.")
}
// Si la condición es falsa, este bloque se salta.
fmt.Println("Programa terminado.")
}

Anatomía de un if:

  • if: La palabra clave que inicia la sentencia condicional.

  • condición: Una expresión booleana (que evalúa a true o false). Go no requiere paréntesis alrededor de la condición (a diferencia de lenguajes como Java o C++).

  • { ... }: Las llaves ({}) delimitan el bloque de código que se ejecutará si la condición es verdadera. Las llaves son obligatorias, incluso si el bloque contiene una sola línea.

Análisis Quirúrgico: Cómo funciona internamente?

Cuando Go encuentra un if statement, evalúa la expresión booleana de la condición. Si el resultado es true, el * puntero de instrucción* (program counter) salta a la primera línea de código dentro del bloque {}. Una vez que ese bloque termina, el puntero de instrucción continúa con la línea de código después del if statement. Si la condición es false, el puntero de instrucción simplemente salta directamente a la línea de código después del bloque {}. Es un salto condicional en el flujo de ejecución.

if-else: La Alternativa

A menudo, quieres ejecutar un bloque de código si una condición es verdadera, y un bloque diferente si esa condición es falsa. Para esto, usas la sentencia if-else.

package main
import "fmt"
func main() {
puntuacion := 75
if puntuacion >= 60 {
fmt.Println("¡Aprobado!")
} else {
fmt.Println("Reprobado. Necesitas estudiar más.")
}
hora := 9
if hora < 12 {
fmt.Println("Buenos días.")
} else {
fmt.Println("Buenas tardes.")
}
}

Anatomía de un if-else:

  • El bloque else se ejecuta solo si la condición del if es falsa.

  • No hay condición para else; simplemente actúa como la ruta por defecto cuando el if no se cumple.

  • Las llaves son obligatorias también para el bloque else.

if-else if-else: Múltiples Caminos

Cuando tienes múltiples condiciones que se excluyen mutuamente, y quieres ejecutar un bloque de código diferente para cada una, puedes encadenar sentencias if-else if-else. Go evaluará las condiciones en orden, y ejecutará el primer bloque cuya condición sea verdadera. Una vez que encuentra una condición verdadera y ejecuta su bloque, el resto de la cadena else if y else se ignoran.

package main
import "fmt"
func main() {
calificacion := 85
if calificacion >= 90 {
fmt.Println("Calificación: A")
} else if calificacion >= 80 { // Esta se evalúa si la anterior fue falsa.
fmt.Println("Calificación: B")
} else if calificacion >= 70 { // Esta se evalúa si las dos anteriores fueron falsas.
fmt.Println("Calificación: C")
} else { // Esta es la "trampa" si ninguna de las anteriores fue verdadera.
fmt.Println("Calificación: F")
}
velocidad := 70
if velocidad < 50 {
fmt.Println("Velocidad normal.")
} else if velocidad >= 50 && velocidad < 80 { // Uso del operador lógico AND (&&)
fmt.Println("Velocidad moderada.")
} else {
fmt.Println("¡Velocidad excesiva!")
}
}

Puntos Clave del if-else if-else:

  • Las condiciones se evalúan de arriba hacia abajo.

  • El primer bloque if o else if cuya condición sea true se ejecuta, y luego la ejecución salta al final de toda la cadena condicional.

  • El bloque else (si está presente) actúa como el caso predeterminado si ninguna de las condiciones if o else if anteriores fue verdadera.

Declaración Corta en if: Inicialización y Condición en una Línea

Go permite una sintaxis muy elegante y común para los if statements: puedes declarar e inicializar una variable * justo antes* de la condición, separada por un punto y coma ;. La variable declarada de esta manera solo será visible (tendrá alcance) dentro del bloque if y cualquier bloque else if/else asociado.

package main
import (
"errors"
"fmt"
"strconv" // Paquete para conversiones de string a número
)
// Una función de ejemplo que podría fallar
func convertirAEntero(s string) (int, error) {
num, err := strconv.Atoi(s) // strconv.Atoi devuelve un int y un error
if err != nil {
return 0, errors.New("Error de conversión: " + err.Error())
}
return num, nil
}
func main() {
// Declaración corta: 'num' y 'err' existen solo dentro del if/else
if num, err := convertirAEntero("123"); err != nil {
fmt.Println("No se pudo convertir '123':", err)
} else {
fmt.Println("Número convertido exitosamente:", num) // num es visible aquí
}
// Intentamos con un valor que causa error
if num, err := convertirAEntero("abc"); err != nil {
fmt.Println("No se pudo convertir 'abc':", err) // err es visible aquí
} else {
fmt.Println("Número convertido exitosamente:", num)
}
// Aquí, 'num' y 'err' no existen. Intentar usarlos resultaría en un error de compilación.
// fmt.Println(num) // Error: undefined: num
}

Ventaja de la Declaración Corta:

Esta sintaxis es un pilar del manejo de errores idiomático en Go. Permite que la verificación del error y el uso de la variable resultante se realicen en el mismo ámbito, promoviendo la claridad y evitando que las variables de error ( como err) se “escapen” a un ámbito más amplio del necesario. Esto reduce la posibilidad de usar un error obsoleto.

Operadores Lógicos: Combinando Condiciones

Puedes combinar múltiples condiciones booleanas usando operadores lógicos:

  • && (AND lógico): Ambas condiciones deben ser verdaderas para que la expresión completa sea verdadera.

  • || (OR lógico): Al menos una de las condiciones debe ser verdadera para que la expresión completa sea verdadera.

  • ! (NOT lógico): Invierte el valor de verdad de una condición.

package main
import "fmt"
func main() {
estaLloviendo := true
haceFrio := false
if estaLloviendo && haceFrio { // true && false -> false
fmt.Println("Ponte un impermeable y un abrigo.")
} else if estaLloviendo || haceFrio { // true || false -> true
fmt.Println("Ponte algo para protegerte del clima.")
} else {
fmt.Println("Disfruta el buen tiempo.")
}
esAdministrador := true
estaLogueado := false
if esAdministrador && !estaLogueado { // true && !false -> true && true -> true
fmt.Println("El administrador necesita iniciar sesión.")
}
}

Con los condicionales (if, else if, else) y la declaración corta, tienes el control total sobre el flujo de tu programa, permitiéndole tomar decisiones complejas y manejar situaciones diversas. Ahora sí que estamos listos para ejercicios!!!


Ejercicios de Programación en Go: Consolidando Condicionales!!!

Estos problemas están diseñados para que practiques la toma de decisiones en tu código utilizando las sentencias if, else if y else. Concéntrate en la lógica condicional y cómo encadenar diferentes escenarios.


Ejer. 1: Clasificador de Números

Contexto: Necesitas una función que determine si un número entero es positivo, negativo o cero.

Requisitos:

  1. Crea una función llamada ClasificarNumero que acepte un int llamado numero como parámetro.

  2. La función no debe devolver ningún valor, sino que debe imprimir en la consola un mensaje indicando la clasificación del número:

    • “El número es positivo.” si es mayor que 0.
    • “El número es negativo.” si es menor que 0.
    • “El número es cero.” si es igual a 0.
  3. En tu función main, llama a ClasificarNumero con al menos tres valores diferentes: uno positivo, uno negativo y cero.

Ejemplo de Salida esperada (parcial):

El número 10 es positivo.
El número -5 es negativo.
El número 0 es cero.

Ejer. 2: Verificador de Edad para Acceso

Contexto: Estás desarrollando un sistema de entrada y necesitas verificar la edad de un usuario para determinar si tiene permitido el acceso a diferentes áreas.

Requisitos:

  1. Crea una función llamada VerificarAcceso que acepte un int llamado edad como parámetro.

  2. La función debe imprimir un mensaje indicando el tipo de acceso permitido, basándose en las siguientes reglas:

    • Si la edad es menor de 18: “Acceso denegado. Eres menor de edad.”
    • Si la edad es entre 18 y 64 (ambos inclusive): “Acceso permitido a todas las áreas.”
    • Si la edad es 65 o mayor: “Acceso permitido con descuento para adultos mayores.”
  3. En tu función main, llama a VerificarAcceso con al menos cuatro edades diferentes que cubran todos los rangos: 16, 25, 65, 70.

Ejemplo de Salida esperada (parcial):

Edad: 16 -> Acceso denegado. Eres menor de edad.
Edad: 25 -> Acceso permitido a todas las áreas.
Edad: 65 -> Acceso permitido con descuento para adultos mayores.

Ejer. 3: Determinar el Mayor de Tres Números

Contexto: Necesitas una función que encuentre el número más grande entre tres valores enteros dados.

Requisitos:

  1. Crea una función llamada EncontrarMayor que acepte tres parámetros int: a, b y c.

  2. La función debe devolver un int que sea el valor más grande de los tres.

  3. Considera que los números pueden ser iguales. Si hay empates, cualquier valor que sea el mayor está bien.

  4. En tu función main, llama a EncontrarMayor con al menos tres conjuntos diferentes de números, imprimiendo el resultado en cada caso.

Ejemplo de Salida esperada (parcial):

Números: 10, 5, 20 -> El mayor es: 20
Números: 7, 7, 3 -> El mayor es: 7
Números: -1, -5, -3 -> El mayor es: -1

Ejer. 4: Verificador de Año Bisiesto

Contexto: Necesitas una función para determinar si un año dado es un año bisiesto.

Requisitos:

  1. Crea una función llamada EsBisiesto que acepte un int llamado año como parámetro.

  2. La función debe devolver un bool que sea true si el año es bisiesto, y false en caso contrario.

  3. Las reglas para un año bisiesto son:

    • Un año es bisiesto si es divisible por 4, excepto si es divisible por 100.
    • Sin embargo, si es divisible por 400, es un año bisiesto.
    • Ejemplos: 2000 es bisiesto, 1900 no es bisiesto, 2004 es bisiesto, 2023 no es bisiesto.
  4. En tu función main, llama a EsBisiesto con al menos cinco años que cubran todos los casos (bisiesto por 4, no bisiesto por 100, bisiesto por 400, y no bisiesto estándar). Imprime el año y si es bisiesto o no.

Ejemplo de Salida esperada (parcial):

Año 2000: Es bisiesto: true
Año 1900: Es bisiesto: false
Año 2004: Es bisiesto: true
Año 2023: Es bisiesto: false

Tómate tu tiempo para intentar resolver cada uno de estos ejercicios. La clave es pensar en las condiciones lógicas y cómo anidarlas o encadenarlas. Una vez que hayas hecho tu mejor esfuerzo, puedes comparar tus soluciones con las que se presentan a continuación.


Solución al Ejer. 1: Clasificador de Números

package main
import "fmt"
// ClasificarNumero determina si un número es positivo, negativo o cero e imprime el resultado.
func ClasificarNumero(numero int) {
if numero > 0 {
fmt.Printf("El número %d es positivo.\n", numero)
} else if numero < 0 {
fmt.Printf("El número %d es negativo.\n", numero)
} else { // Si no es mayor que 0 y no es menor que 0, debe ser 0.
fmt.Printf("El número %d es cero.\n", numero)
}
}
func main() {
fmt.Println("--- Desafío 1: Clasificador de Números ---")
ClasificarNumero(10)
ClasificarNumero(-5)
ClasificarNumero(0)
ClasificarNumero(42)
ClasificarNumero(-1)
}

Solución al Ejer. 2: Verificador de Edad para Acceso

package main
import "fmt"
// VerificarAcceso determina el tipo de acceso permitido según la edad del usuario.
func VerificarAcceso(edad int) {
fmt.Printf("Edad: %d -> ", edad)
if edad < 18 {
fmt.Println("Acceso denegado. Eres menor de edad.")
} else if edad >= 18 && edad <= 64 { // Mayor o igual a 18 Y menor o igual a 64
fmt.Println("Acceso permitido a todas las áreas.")
} else { // Si no es menor de 18 y no está entre 18-64, debe ser 65 o más.
fmt.Println("Acceso permitido con descuento para adultos mayores.")
}
}
func main() {
fmt.Println("\n--- Desafío 2: Verificador de Edad para Acceso ---")
VerificarAcceso(16)
VerificarAcceso(18) // Límite inferior del segundo rango
VerificarAcceso(25)
VerificarAcceso(64) // Límite superior del segundo rango
VerificarAcceso(65) // Límite inferior del tercer rango
VerificarAcceso(70)
VerificarAcceso(5) // Un caso muy bajo
}

Solución al Ejer. 3: Determinar el Mayor de Tres Números

package main
import "fmt"
// EncontrarMayor encuentra el número más grande entre tres valores enteros.
func EncontrarMayor(a, b, c int) int {
mayor := a // Asumimos que 'a' es el mayor inicialmente
// Comparamos 'b' con el actual 'mayor'. Si 'b' es mayor, actualizamos 'mayor'.
if b > mayor {
mayor = b
}
// Comparamos 'c' con el actual 'mayor'. Si 'c' es mayor, actualizamos 'mayor'.
if c > mayor {
mayor = c
}
return mayor
}
func main() {
fmt.Println("\n--- Desafío 3: Determinar el Mayor de Tres Números ---")
fmt.Printf("Números: %d, %d, %d -> El mayor es: %d\n", 10, 5, 20, EncontrarMayor(10, 5, 20))
fmt.Printf("Números: %d, %d, %d -> El mayor es: %d\n", 7, 7, 3, EncontrarMayor(7, 7, 3))
fmt.Printf("Números: %d, %d, %d -> El mayor es: %d\n", -1, -5, -3, EncontrarMayor(-1, -5, -3))
fmt.Printf("Números: %d, %d, %d -> El mayor es: %d\n", 100, 50, 50, EncontrarMayor(100, 50, 50))
fmt.Printf("Números: %d, %d, %d -> El mayor es: %d\n", 5, 12, 8, EncontrarMayor(5, 12, 8))
fmt.Printf("Números: %d, %d, %d -> El mayor es: %d\n", 30, 20, 40, EncontrarMayor(30, 20, 40))
}

Solución al Ejer. 4: Verificador de Año Bisiesto

package main
import "fmt"
// EsBisiesto determina si un año dado es un año bisiesto.
func EsBisiesto(año int) bool {
// Regla 1: Divisible por 4
esDivisiblePor4 := (año%4 == 0)
// Regla 2: Divisible por 100
esDivisiblePor100 := (año%100 == 0)
// Regla 3: Divisible por 400
esDivisiblePor400 := (año%400 == 0)
// Aplicamos las reglas combinadas con operadores lógicos:
// (Divisible por 4 Y NO divisible por 100) O (Divisible por 400)
if (esDivisiblePor4 && !esDivisiblePor100) || esDivisiblePor400 {
return true
} else {
return false
}
}
func main() {
fmt.Println("\n--- Desafío 4: Verificador de Año Bisiesto ---")
// Casos de prueba
fmt.Printf("Año %d: Es bisiesto: %t\n", 2000, EsBisiesto(2000)) // Bisiesto por 400
fmt.Printf("Año %d: Es bisiesto: %t\n", 1900, EsBisiesto(1900)) // No bisiesto por 100
fmt.Printf("Año %d: Es bisiesto: %t\n", 2004, EsBisiesto(2004)) // Bisiesto por 4
fmt.Printf("Año %d: Es bisiesto: %t\n", 2023, EsBisiesto(2023)) // No bisiesto estándar
fmt.Printf("Año %d: Es bisiesto: %t\n", 2024, EsBisiesto(2024)) // Bisiesto por 4
fmt.Printf("Año %d: Es bisiesto: %t\n", 1600, EsBisiesto(1600)) // Bisiesto por 400
}

Listo Muchachones, nos vemos en el siguiente Capitulo, activitos!!!

Next: Go desde Cero, Pero Bien: Ejercicios HackerRank (Vol. 1)
Foto Cesar Fernandez

¿Lo rompiste? ¿Lo mejoraste?

Gracias por llegar hasta el final. Escribo estos posts para organizar mis propias ideas y, con suerte, para ahorrarle a alguien más el dolor de cabeza que yo ya pasé. Me encuentras en LinkedIn o puedes ver más de mi trabajo en GitHub.


Serie: Curso Profesional de Go