Las funciones anónimas, también conocidas como funciones sin nombre, son un concepto interesante en programación y Go no es la excepción al implementarlas. Estas funciones se crean para ser utilizadas una sola vez y no se pueden referenciar de nuevo, pues carecen de un nombre. Este enfoque es útil cuando estamos absolutamente seguros de que la funcionalidad solo se necesita ejecutar una única vez.
¿Cómo implementamos funciones anónimas en Go?
Veamos cómo se utiliza el concepto de funciones anónimas en el código Go. Primero, crearemos un archivo llamado functions.go. Luego, dentro de este archivo, definimos el paquete principal y una función main. Se propone crear una variable x e implementar una función anónima que duplique su valor.
package main
funcmain(){ x :=5 y :=func()int{return x *2}()println(y)}
En este bloque, la función para obtener el doble del valor de x se declara e inmediatamente se invoca. La función anónima se asigna a una variable y, que se imprime a continuación. Sin embargo, si necesitamos reutilizar esta función con otro valor, corremos el riesgo de duplicar código.
¿Cuáles son las desventajas de repetir código con funciones anónimas?
El ejemplo anterior nos mostró que si intentamos reutilizar el código de la función con otra variable, estaríamos repitiendo código, lo cual va en contra del principio DRY (Don't Repeat Yourself). Este principio promueve evitar la duplicación en el diseño de software.
package main
funcmain(){ x :=5 y :=func()int{return x *2}()println(y) z :=10 doubleZ :=func()int{return z *2}()println(doubleZ)}
Aunque el enfoque puede funcionar, no es una buena práctica. Repetiríamos el mismo bloque de código en lugar de abstraerlo en una función.
¿Cómo se utilizan funciones anónimas con Goroutines?
Otra utilidad clave de las funciones anónimas es en la ejecución concurrente con Goroutines en Go. Las funciones anónimas nos permiten realizar procesos largos sin bloquear el flujo general del programa.
package main
import("fmt""time")funcmain(){ done :=make(chanbool)gofunc(){ fmt.Println("Iniciando la función...") time.Sleep(5* time.Second) fmt.Println("Función terminada.") done <-true}()<-done
fmt.Println("Programa completado.")}
En este ejemplo, hemos usado una función anónima para simular un proceso largo que espera 5 segundos antes de finalizar. Esto demuestra la potencia de las funciones anónimas al permitirnos ejecutar código de manera concurrente usando Goroutines.
¿Cuándo es recomendable usar funciones anónimas?
El uso de funciones anónimas es práctico en situaciones donde:
Necesitamos realizar una operación sencilla una sola vez.
Deseamos aplicar funcionalidad en tiempo de ejecución sin saturar el espacio de nombres con funciones no reutilizables.
En conjunción con Goroutines para manejar procesos concurrentes.
Sin embargo, es crucial recordar que contar con bloques de código duplicado complica el mantenimiento del mismo y no es recomendado. Por lo tanto, el diseño en Go debe tener en cuenta el equilibrio entre funcionalidad, simplicidad y reutilización.
¡Sigue explorando y practicando para afianzar tu conocimiento en Go y sus diversas herramientas! La práctica constante y el aprendizaje continuo son claves para un desarrollo exitoso en la programación.
También se pueden hacer funciones que anónimas que reciben parámetros. Solamente hay que agregar el valor del mismo en los paréntesis del final
z:=func(n int) int {return n *2}(5)
Aunque la idea es correcta, no es un approach común (generalmente las funciones anónimas no llevan parámetros), ya que, la idea de los parámetros es hacer las funciones re-usables, y una función anónima no es reusable (porque no tienen un nombre para ser re-usadas). Si ya estás "hardcodeando" el 5 en los paréntesis de la invocación, pues es más simple quitar el parámetro y poner el 5 directamente en el lugar de la n.
package main
import("fmt""time")// Funciones anónimasfunc main(){func(){println("Hello")}()x:=5y:=func() int {return x *2}() fmt.Println(y)c:=make(chan int) go func(){ fmt.Println("Starting function") time.Sleep(2* time.Second) fmt.Println("Finishing function") c <-1}() fmt.Println(<-c)}
un pequeño aporte relacionado a los antivirus, en caso alguien llegase a tener Kaspersky, Avast, entre otros, al momento de querer correr el archivo functions.go le arojara un falso positivo de Troyano, la solución más fácil es cambiarle el nombre de functions.go a main.go como se venía trabajando en los videos anteriores, y no habrá problemas al ejecutar el código
Una función anónima es una función definida internamente dentro de un bloque de código, y que no tiene identificador o nombre. Este tipo de funciones no son reutilizables como paquetes, siendo utilizadas únicamente dentro del bloque de código en el que son declaradas.
Una solución para no definir la función anónima dos veces, es declarandola pero no invocarla con los () al final, con esto podemos llamarla más adelante con la variable
package main
import"fmt"func main(){x:=5y:=func(num int) int {return num *2}z:=8 fmt.Println(y(x)) fmt.Println(y(z))}
Aunque ya no sería tan anónima xd
Código de la clase con comentarios explicando:
package functions
import (
"fmt"
"time"
)
// anon func's are not very recommended for DRY purposes. Only use it when it is necessary.
func anon() {
x := 5
// Anonymous func 1
y := func(x int) int {
return x * 2
}
fmt.Println("y anon func: ", y(x))
// Anonymous func 2 (it calls directly the param and calls itself)
z := func() int {
return x * 2
}()
fmt.Println("y anon func: ", z)
// 3rd Anonymous way: lambda Goroutine in a channel
// Create channel for blocking Gorouting until msg arrives
c := make(chan int)
// anon Goroutine
go func() {
// Exec func logic in Goroutine
fmt.Println("Starting Goroutine anon func...")
time.Sleep(1 * time.Second)
fmt.Println("Goroutine ended")
// Send int to c channel
c <- 1
}() // calls itself
// Waits until receiving the msg in c channel
<-c
}
func Functions() {
anon()
}
De forma similar a JS o Python:
package main
import (
"fmt"
)
func main() {
myNum:= 5
double := func(num int) int {
return num * 2
}
fmt.Println(double(myNum))
}
Pregunta, porque al realizar el siguiente código, en algunas ocasiones no se visualiza todas las impresiones en la terminal?
package main
import("fmt""time")func main(){ fmt.Println("Inicia programa")c:=make(chan int,2) go func(){ fmt.Println("Starting Function1") time.Sleep(2* time.Second) fmt.Println("End function1") c <-1}() go func(){ fmt.Println("Starting Function2") time.Sleep(2* time.Second) fmt.Println("End function2") c <-2}()<-c
fmt.Println("Finaliza el programa")}
output:
Inicia programa
Starting Function2
Starting Function1
End function1
Finaliza el programa
Te sucede porque solo estas esperando a recibir un solo mensaje por el canal c. Intenta duplicando la linea: <-c. De esta forma el programa finalizara si solo si recibe exactamente 2 mensajes por ese canal.
Cuando el hilo Main deja de esperar termina el programa y los hilos que estaban todavia haciendo algo mueren. Por eso hay un println que no llega a aparecer
Estas funciones anónimas acceden a variables que están en su entorno, sin ser enviadas como argumentos. Es como si fueran variables globales. Las funciones con nombre pueden hacer lo mismo?