En el ecosistema de Go, las funciones son consideradas "ciudadanos de primera clase". Esto significa que pueden ser asignadas a variables, pasadas como argumentos a otros métodos y retornadas como resultados, lo que permite un estilo de programación flexible y modular.
Estructura y Definición de Funciones
Para declarar una función se utiliza la palabra clave func. La sintaxis básica incluye el nombre, los parámetros entre paréntesis, el tipo de retorno y el cuerpo de la función.
func calcularArea(base float64, altura float64) float64 {
return base * altura
}
Simplificación de parámetros y valores múltiples
Si varios parámetros consecutivos comparten el mismo tipo, se puede declarar el tipo solo al final. Además, Go permite retornar múltiples valores simultáneamente, una característica muy utilizada para el manejo de errores.
// Parámetros simplificados y retorno múltiple
func operaciones(a, b int) (suma, resta int) {
suma = a + b
resta = a - b
return // Retorno implícito de variables nombradas
}
Parámetros Variádicos
Una función puede recibir un número indeterminado de argumentos utilizando la elipsis .... Internamente, Go trata estos argumentos como un slice del tipo especificado.
func sumarTodo(valores ...int) int {
total := 0
for _, v := range valores {
total += v
}
return total
}
// Uso:
// resultado := sumarTodo(10, 20, 30, 40)
La Sentencia defer
La instrucción defer pospone la ejecución de una función hasta que la función que la contiene finaliza (ya sea por un return o al llegar al final del bloque). Las llamadas a defer se apilan en una estructura LIFO (Last-In, First-Out).
func flujoEjecucion() {
fmt.Println("Paso 1")
defer fmt.Println("Paso Final (defer 1)")
defer fmt.Println("Paso Intermedio (defer 2)")
fmt.Println("Paso 2")
}
/* Salida:
Paso 1
Paso 2
Paso Intermedio (defer 2)
Paso Final (defer 1)
*/
Enteracción entre defer y valores de retorno
Es crucial entender que return no es una operación atómica. Primero se asigna el valor al retorno y luego se ejecutan los defer antes de la instrucción RET final. Esto permite que los defer modifiquen parámetros de retorno nombrados.
func incrementoNombrado() (resultado int) {
defer func() {
resultado++
}()
return 10 // El valor final será 11
}
Ámbito de las Variables
- Variables Globales: Definidas fuera de las funciones, accesibles en todo el paquete o de forma externa si empiezan con mayúscula.
- Variables Locales: Definidas dentro de una función o bloque (if, for, switch), solo son visibles en ese contexto.
Funcoines Anónimas y Closures
Las funciones aónimas no poseen nombre y suelen definirse en línea para tareas específicas. Un Closure ocurre cuando una función anónima captura variables de su entorno exterior.
func generadorPrefijo(prefijo string) func(string) string {
return func(nombre string) string {
return fmt.Sprintf("%s %s", prefijo, nombre)
}
}
func main() {
saludoFormal := generadorPrefijo("Sr.")
fmt.Println(saludoFormal("Gómez")) // Sr. Gómez
}
Funciones Incorporadas
Go ofrece un conjunto de funciones nativas para operaciones esenciales sin necesidad de importar paquetes:
| Función | Propósito |
|---|---|
make |
Inicializa tipos de referencia (slice, map, chan). |
new |
Reserva memoria para tipos de valor, devuelve un puntero. |
len / cap |
Obtiene longitud y capacidad de estructuras de datos. |
append |
Agrega elementos a un slice. |
panic / recover |
Manejo de errores críticos y recuperación de estados de pánico. |
Manejo de Pánico y Recuperación
El pánico detiene el flujo normal del programa. Sin embargo, recover puede capturar un pánico y permitir que el programa continúe, siempre y cuando se invoque dentro de un defer.
func procesoCritico() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recuperado de un error grave:", r)
}
}()
fmt.Println("Iniciando...")
panic("Fallo crítico en el sistema")
fmt.Println("Esto nunca se ejecutará")
}