1 Fundamentos de Funciones

En programación, una función es un fragmento de código que logra una tarea específica y puede tener parámetros de entrada y valores de retorno. En el lenguaje Go, las funciones se utilizan ampliamente para organizar y reutilizar código. Utilizar funciones de manera efectiva puede hacer que el código sea más conciso, altamente legible y fácil de mantener.

Las funciones son un componente fundamental del lenguaje Go, y comprender cómo declarar y definir funciones es crucial para escribir código eficiente y legible.

2 Definición de Funciones

2.1 Declaración de Funciones

En el lenguaje Go, la forma general de declarar una función es:

func nombreFuncion(parametros) tipoRetorno {
    // Cuerpo de la función
}

Desglosemos estos componentes:

  1. La palabra clave func se utiliza para declarar una función.
  2. nombreFuncion es el nombre de la función, siguiendo las convenciones de nomenclatura del lenguaje Go. Una función con una letra inicial en mayúscula es exportable, lo que significa que es visible fuera del paquete; una función con una letra inicial en minúscula no es exportable y solo se puede utilizar dentro del mismo paquete.
  3. parametros es la lista de parámetros que recibe la función, separados por comas. Se necesita especificar el tipo de cada parámetro, y si varios parámetros tienen el mismo tipo, el tipo solo se especifica una vez.
  4. tipoRetorno es el tipo del valor de retorno de la función. Si la función no devuelve un valor, esta parte se puede omitir. Si la función devuelve múltiples valores, deben estar encerrados entre paréntesis.

Por ejemplo, podemos declarar una función sencilla para calcular la suma de dos enteros:

func Sumar(a int, b int) int {
    return a + b

En este ejemplo, el nombre de la función es Sumar, toma dos parámetros de tipo int (a y b), y devuelve su suma con el tipo de retorno int.

2.2 Lista de Parámetros

La lista de parámetros define qué parámetros acepta la función y el tipo de cada parámetro. Los parámetros son un tipo especial de variable utilizada para pasar datos a una función.

func Saludar(nombre string, edad int) {
    fmt.Printf("¡Hola, %s! Tienes %d años.\n", nombre, edad)
}

En esta función Saludar, nombre y edad son parámetros. El tipo de nombre es string, y el tipo de edad es int. Al llamar a esta función, se deben proporcionar valores reales para estos parámetros.

2.3 Tipos de Retorno

Las funciones pueden devolver resultados computados, y el tipo de retorno define el tipo de datos del valor de retorno de la función. Las funciones pueden no tener un valor de retorno, o pueden tener uno o más valores de retorno.

Si una función tiene múltiples valores de retorno, sus tipos deben estar encerrados entre paréntesis durante la declaración:

func Dividir(dividendo, divisor float64) (float64, error) {
    if divisor == 0 {
        return 0, errors.New("no se puede dividir por cero")
    }
    return dividendo / divisor, nil
}

La función Dividir aquí devuelve dos valores: el cociente y un mensaje de error. Si el divisor es cero, se devuelve un error.

2.4 Parámetros Variádicos

En Golang, cuando no estamos seguros de cuántos parámetros pasará el llamante al definir una función, podemos usar parámetros variádicos. Los parámetros variádicos se indican con un espacio de tres puntos ..., lo que significa que la función puede aceptar cualquier número de parámetros. Esto es muy útil cuando se trata de una cantidad incierta de datos o se implementan ciertos tipos de funciones como funcionalidades de formato, resumen o iteración.

Escenarios de Aplicación

Los parámetros variables se utilizan comúnmente en los siguientes escenarios:

  1. Concatenación de cadenas: como las funciones fmt.Sprintf y strings.Join.
  2. Procesamiento de matrices/rebanadas: al tratar con matrices o rebanadas de longitudes variables, como calcular la suma o concatenar múltiples rebanadas.
  3. Registro y manejo de errores: al manejar múltiples errores o registrar múltiples información de registro, como log.Printf o funciones personalizadas de resumen de errores.
  4. Funciones auxiliares: utilizadas en APIs o bibliotecas para proporcionar a los usuarios formas más flexibles de llamar a funciones.

Uso de parámetros variables

Aquí tienes un ejemplo sencillo de uso de parámetros variables:

// Define una función que toma un número variable de parámetros enteros y devuelve su suma
func Suma(nums ...int) int {
    total := 0
    for _, num := range nums {
        total += num
    }
    return total
}

func main() {
    // Puedes pasar cualquier número de parámetros
    fmt.Println(Suma(1, 2))          // Salida: 3
    fmt.Println(Suma(1, 2, 3, 4))    // Salida: 10
    
    // También puedes pasar una slice y usar los puntos suspensivos después de la slice
    numeros := []int{1, 2, 3, 4, 5}
    fmt.Println(Suma(numeros...))    // Salida: 15
}

En la función Suma, nums es una slice de enteros que contiene todos los parámetros pasados a la función Suma. Podemos usar un bucle range para iterar a través de esta slice y calcular la suma.

Es importante tener en cuenta que los parámetros variables dentro de la función son en realidad una slice, por lo que se pueden usar todas las operaciones relacionadas con las slices. Cuando necesitas pasar una slice como un parámetro variable a una función, solo agrega unos puntos suspensivos ... después de la slice.

El uso de parámetros variables puede hacer que las llamadas a funciones sean más flexibles y concisas, pero también tendrá un ligero impacto en el rendimiento, ya que el uso de parámetros variables implica la creación de slices y la asignación de memoria. Por lo tanto, se debe tener cuidado cuando existan requisitos estrictos de rendimiento.

Consejo: Se proporcionará una explicación detallada sobre las slices en capítulos posteriores. Si tienes experiencia con otros lenguajes de programación, puedes pensar temporalmente en ellas como arrays.

3 Llamando funciones

3.1 Llamadas básicas a funciones

Llamar a una función significa ejecutar el código de la función. En Go, llamar a una función definida es muy sencillo, solo usa el nombre de la función y pasa los parámetros apropiados. Por ejemplo:

resultado := sumar(3, 4)
fmt.Println(resultado)  // Salida: 7

En este ejemplo, se llama a la función sumar y se pasan dos enteros como parámetros, y luego el resultado devuelto se asigna a la variable resultado.

3.2 Pasar parámetros

Cuando se pasan parámetros a una función, Go por defecto utiliza el paso por valor, lo que significa pasar una copia del valor del parámetro, y los datos originales no serán modificados. Sin embargo, si quieres que la función modifique variables externas o por razones de rendimiento, puedes usar el paso por referencia, como utilizar punteros o pasar structs grandes.

Aquí tienes ejemplos de paso por valor y paso por referencia:

// Ejemplo de paso por valor
func doble(valor int) {
    valor *= 2
}

// Ejemplo de paso por referencia
func doblePtr(valor *int) {
    *valor *= 2
}

func main() {
    valor := 3
    doble(valor)
    fmt.Println(valor)  // Salida: 3, el valor permanece sin cambios

    doblePtr(&valor)
    fmt.Println(valor)  // Salida: 6, el valor se duplica
}

En el ejemplo anterior, la función doble intenta duplicar el valor pasado, pero solo duplica su copia, dejando la variable original valor sin cambios. Sin embargo, la función doblePtr cambia el valor de la variable original al recibir un puntero a una variable entera como parámetro.