domingo, 25 de noviembre de 2018

Funciones anónimas y closures en Go

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.

El siguiente código declara una función anónima dentro de la función main(), la cual sólo tiene visibilidad dentro de esta función.

package main

import "fmt"

func main() {

   // Ejemplo basico de funcion anonima
   var num int = 0

   incrementar := func() int {
      num++
      return num
   }

   fmt.Println("Num: ", num)  // 0
   fmt.Println("Num: ", incrementar())  // 1
   fmt.Println("Num: ", incrementar())  // 2
}

closure

Un closure es una implementación de una función anónima como retorno de una función principal. Esta técnica es muy útil, ya que permite que la función principal pueda ser asignada o delegada a una "variable" que es en sí el closure. En ese momento, las variables de la función principal se registran o inicializan y el control pasa al closure.

Cuando se invoca al closure, internamente llama a la sentencia return, que es la que tiene la función anónima con el bloque de código de la operativa.

Para ver más claro esto, vamos a implementar el código anterior mediante un closure:

package main

import "fmt"

func main() {

  // Ejemplo basico de closure
   incr := increment()

   for i := 1; i < 10; i++ {
      fmt.Println("incr() > ", incr())
   }

}

// Funcion que retorna una funcion anonima
func increment() func() int {
   var num int = 0

   return func() int {
      num++
      return num
   }
}

También podemos utilizar parámetros en nuestros closures. Para ello, los parámetros se definen en la función de retorno.

package main

import "fmt"

func main() {

   // Ejemplo de closure con parametro
   acumulador := acumular()

   fmt.Println("acumulador() > ", acumulador(4))  // 4
   fmt.Println("acumulador() > ", acumulador(6))  // 10
   fmt.Println("acumulador() > ", acumulador(20)) // 30

}

// Funcion anonima con parametro
func acumular() func(incremento int) int {
   var num int = 0

   return func(incremento int) int {
      num += incremento
      return num
   }
}

El código anterior es muy básico, pero podemos implementar operativas más complejas, como la secuencia Fibonacci:

package main

import "fmt"

func main() {

   // Implementacion de la secuencia Fibonacci
   fmt.Println("Secuencia Fibonacci")

   proximaSecuencia := fibonacci()

   for i := 1; i < 10; i++ {
      fmt.Println(proximaSecuencia())
   }

 }

// Secuencia Fibonacci
func fibonacci() func() int {
   var num1, num2 int = 0, 1

   return func() int {
      var result int = num1 + num2
      num1 = num2
      num2 = result
      return result
   }
}

Enlaces de interés

No hay comentarios:

Publicar un comentario