Functional literals

A functional literal just represents an anonymous function. You can assign functional literal to a variable:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. f := func() { fmt.Println("Hello, 中国!") }
  7. f()
  8. }

Or invoke functional literal directly (Please notice the () at the end of functional literal):

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. func() { fmt.Println("Hello, 中国!") }()
  7. }

The above 2 programs both output “Hello, 中国!“.

Functional literal is also a closure, so it can access the variables of its surrounding function. Check the following example which your real intention is 1 and 2 are printed:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func main() {
  7. for i := 1; i <= 2; i++ {
  8. go func() {fmt.Println(i)}()
  9. }
  10. time.Sleep(time.Second)
  11. }

But the output is:

  1. 3
  2. 3

The cause is the func goroutines don’t get the opportunity to run until the main goroutine sleeps, and at that time, the variable i has been changed to 3. Modify the above program as follows:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func main() {
  7. for i := 1; i <= 2; i++ {
  8. go func() {fmt.Println(i)}()
  9. time.Sleep(time.Second)
  10. }
  11. }

The func goroutine can run before i is changed, so the running result is what you expect:

  1. 1
  2. 2

But the idiom method should be passing i as an argument of the functional literal:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func main() {
  7. for i := 1; i <= 2; i++ {
  8. go func(i int) {fmt.Println(i)}(i)
  9. }
  10. time.Sleep(time.Second)
  11. }

In above program, When “go func(i int) {fmt.Println(i)}(i)“ is executed (Note: not goroutine is executed.), i defined in main() is assigned to func‘s local parameter i. And the result is:

  1. 1
  2. 2

P.S. You should notice, If you pass an argument while not use it, the Go compiler doesn’t complain, but the closure will use the variable inherited from the parent function. That means the following statement:

  1. go func(int) {fmt.Println(i)}(i)

equals to:

  1. go func() {fmt.Println(i)}()

References:
The Go Programming Language Specification;
A question about passing arguments to closure;
Why add “()” after closure body in Golang?.