Tracks
/
Go
Go
/
Temario
/
Funciones
Fu

Funciones en Go

1 ejercicio

Acerca de Funciones

Una función te permite agrupar código en una unidad reutilizable. Consta de la palabra clave func, el nombre de la función y una lista de cero o más parámetros y tipos, separada por comas y entre paréntesis.

Parámetros de la función

Todos los parámetros deben tener un tipo explícito; no hay inferencia de tipos para los parámetros. Los parámetros no tienen valores predeterminados, así que todos los parámetros de una función son obligatorios.

import "fmt"

// No parameters
func PrintHello() {
    fmt.Println("Hello")
}

// One parameter
func PrintHelloName(name string) {
  fmt.Println("Hello " + name)
}

Los parámetros del mismo tipo se pueden declarar juntos, seguidos de una sola declaración de tipo.

import "fmt"

func PrintGreetingName(greeting, name string) {
  fmt.Println(greeting + " " + name)
}

Parámetros vs. argumentos

Veamos rápidamente dos términos que suelen confundirse: parameters y arguments. Los parámetros de una función son los nombres definidos en la firma de la función, como greeting y name en la función PrintGreetingName de arriba. Los argumentos de una función son los valores concretos que se pasan a los parámetros cuando llamamos a la función. Por ejemplo, en el ejemplo de abajo, "Hello" y "Katrina" son los argumentos que se pasan a los parámetros greeting y name:

PrintGreetingName("Hello", "Katrina")

Valores de retorno

Después de los parámetros de la función vienen cero o más valores de retorno, que también deben tener un tipo explícito. Los valores de retorno únicos se escriben sin paréntesis; los valores de retorno múltiples se encierran entre paréntesis. Las funciones devuelven los valores al código que las llamó usando la palabra clave return. Puede haber varias sentencias return en una función. La ejecución de la función termina en cuanto se topa con una de esas sentencias return. Si una función va a devolver varios valores, estos se separan con comas. En el concepto enlazado puedes encontrar más información sobre el uso idiomático de los valores de retorno múltiples.

func Hello(name string) string {
  return "Hello " + name
}

func HelloAndGoodbye(name string) (string, string) {
  return "Hello " + name, "Goodbye " + name
}

Cómo llamar a funciones

Para llamar a una función, se escribe el nombre de la función y se pasan argumentos para cada uno de sus parámetros entre paréntesis.

import "fmt"

// No parameters, no return value
func PrintHello() {
    fmt.Println("Hello")
}
// Called like this:
PrintHello()

// One parameter, one return value
func Hello(name string) string {
  return "Hello " + name
}
// Called like this:
greeting := Hello("Dave")

// Multiple parameters, multiple return values
func SumAndMultiply(a, b int) (int, int) {
    return a+b, a*b
}
// Called like this:
aplusb, atimesb := SumAndMultiply(a, b)

Valores de retorno con nombre y retorno desnudo

Además de los parámetros, los valores de retorno pueden tener nombre de forma opcional. Si se usan valores de retorno con nombre, una sentencia return sin argumentos devolverá esos valores. A esto se le llama un retorno «desnudo».

func SumAndMultiplyThenMinus(a, b, c int) (sum, mult int) {
    sum, mult = a+b, a*b
    sum -= c
    mult -= c
    return
}

Paso por valor y paso por referencia

También es importante aclarar el concepto de paso por valor y paso por referencia.

Primero, aclaremos el paso por valor. En el ejemplo de abajo, cuando pasamos la variable val a la función MultiplyByTwo, pasamos una copia de val. Por eso, newVal tiene el valor actualizado 4, pero la variable original val sigue siendo 2. Detrás de escena, Go básicamente hace una copia del valor original, de modo que la función solo modifica esa copia, también conocida como v.

val := 2
func MultiplyByTwo(v int) int {
    v = v * 2
    return v
}
newVal := MultiplyByTwo(val)
// newval is 4, val is still 2 because only a copy of its value was passed into the function

En sentido estricto, en Go todos los argumentos se pasan por valor, es decir, se hace una copia del valor o de los datos que se pasan a la función. Pero si no quieres hacer una copia de los datos que se pasan a una función y quieres cambiar esos datos dentro de la función, entonces deberías usar pointers como argumentos, lo que se conoce como paso por referencia.

Punteros

Usamos un pointer para lograr el paso por referencia. Al pasar argumentos pointer a una función, podemos modificar los datos subyacentes que se pasaron a la función en lugar de operar solo sobre una copia de esos datos.

Por ahora, basta con saber que los tipos de puntero se reconocen por el * que va delante del tipo en la firma de la función.

func HandlePointers(x, y *int) {
    // Some logic to handle integer values referenced by pointers x and y
}

Si el concepto de pointer te resulta confuso, no te preocupes. Más adelante en el temario tenemos una sección dedicada a ayudarte a dominar los punteros.

Excepciones

Ten en cuenta que slices y maps son excepciones a la regla mencionada arriba. Cuando pasamos un slice o un map como argumentos a una función, se tratan como tipos puntero aunque no haya un * explícito en el tipo. Esto significa que si pasamos un slice o un map a una función y modificamos sus datos subyacentes, los cambios se reflejarán en el slice o el map originales.

Otros tipos de funciones

Las funciones en Go se consideran ciudadanos de primera clase, lo que las hace muy potentes. Hay varios otros conceptos relacionados con las funciones, como los métodos y las funciones anónimas, que conocerás más adelante en tu recorrido.

Editar en GitHub El enlace se abre en una ventana o pestaña nueva

Aprende Funciones