Anonymous Functions in GO

  • Anonymous functions are defined where they are used, do not need to have a name and lead to more compact code that is easier to understand.
  • function.go is a simple program with a function definition and call.
  • Its behavior is exactly as you would expect.
/* function.go */
package main
import "fmt"

func myFunc(i int){
   fmt.Printf("hello from function %2d\n", i);
}

func main() {
   for i := 0; i < 10; i++ {
      myFunc(i)
   }
}

The output of this program is:

hello from function  0
hello from function  1
hello from function  2
hello from function  3
hello from function  4
hello from function  5
hello from function  6
hello from function  7
hello from function  8
hello from function  9
  • The program anonFunc.go demonstrates an anonymous function.
  • Here the function is declared as and when required and is not given a name (hence anonymous).
  • The arguments to the function are provided in the round brackets, (. . .) at the end of func.
/* anonFunc.go */
package main
import "fmt"

func main() {
   for i := 0; i < 10; i++ {
      func(i int){
         fmt.Printf("hello from function %2d\n", i);
      }(i)
   }
}
  • The output is the same as before.
  • By adding go before func, as shown in anonFuncGo.go (below), we can create a goroutine, so that 10 goroutines execute in concurrently.
  • This program is incorrect as it does not use synchronization.
/* anonFuncGo.go (incorrect!)*/
package main
import ( "fmt" )

func main() {
   for i := 0; i < 10; i++ {
      go func(i int){
         fmt.Printf("hello from function %2d\n", i);
      }(i)
   }
}
  • If you run this program repeatedly using the command go run anonFuncGo.go you will get incomplete output.
  • In some cases nothing is printed, in other cases incomplete output is obtained.
  • This is caused by lack of synchronization.
  • The correct program is as follows:
/* anonFuncGOCorrect.go */
package main
import ( "fmt"; "sync" )

func main() {
   var wg sync.WaitGroup
   wg.Add(10)
   for i := 0; i < 10; i++ {
      go func(i int){
         fmt.Printf("hello from function %2d\n", i);
         wg.Done()
      }(i)
   }
   wg.Wait()
}
  • In this case a synchronization variable wg is declared and initialized to 10.
  • Whenever a goroutine func completes, wg is decremented by 1 using wg.Done().
  • At the end the program waits for all goroutines to complete (i.e. wg to become 0) using wg.Wait().
  • Here is a typical output:
hello from function  9
hello from function  2
hello from function  6
hello from function  5
hello from function  8
hello from function  4
hello from function  3
hello from function  1
hello from function  7
hello from function  0
  • All 10 goroutines complete, but the order of execution is jumbled.
  • This is because all goroutines are concurrent and we have no control over when one starts or finishes.
  • If your run this program repeatedly, you will see that the order of completion of goroutines is different, but all 10 goroutrines will complete successfully.