Go to variable variable

I am reading "CreateSpace Introduction to Programming in Go 2012"

and on page 86 I found this evil magic

func makeEvenGenerator() func() uint { i := uint(0) return func() (ret uint) { ret = i i += 2 return } } // here how it called nextEven := makeEvenGenerator() fmt.Println(nextEven()) fmt.Println(nextEven()) fmt.Println(nextEven()) 

1) Why is i not reset? 2) nextEven() ) returns and is uint or Println so smart that it can work with everything?

+6
source share
3 answers

For clarity, I'll assign names to both functions:

 func makeEvenGenerator() func() uint { // call this "the factory" i := uint(0) return func() (ret uint) { // call this "the closure" ret = i i += 2 return } } 

factory returns a closure - functions are citizens of the first class in Go, that is, they can be right expressions, for example:

 f := func() { fmt.Println("f was called"); } f() // prints "f was called" 

In your code, closure wraps around the factory context, this is called lexical scope. This is why the variable i is available inside the closure, not as a copy, but as a reference to i .

Closing uses a named return value called ret . This means that inside the closure you implicitly declared ret and at the point return , any value of ret will be returned.

This line:

 ret = i 

will assign the current value of i to ref . He will not change i . However, this line:

 i += 2 

changes the value of i the next time a closure is called.


Here you will find a small closing example that I wrote for you. This is not very useful, but, in my opinion, illustrates very well the scope, purpose and use of closures:

 package main import "fmt" func makeIterator(s []string) func() func() string { i := 0 return func() func() string { if i == len(s) { return nil } j := i i++ return func() string { return s[j] } } } func main() { i := makeIterator([]string{"hello", "world", "this", "is", "dog"}) for c := i(); c != nil; c = i() { fmt.Println(c()) } } 
+9
source

1) Why am I not rebooting?

Closing in Go captures variables by reference. This means that the inner function contains a reference to the variable i in the outer region, and each call to it refers to the same variable.

2) nextEven () return and uint or Println is so smart that it can work with everything?

fmt.Println() (along with fmt.Print() , fmt.Fprint() , etc.) most types can work. He prints his arguments in the "default format". This is the same as typing with fmt.Printf() using the verb %v .

+4
source

The variable in the closure does not contain a code segment or context.

0
source

Source: https://habr.com/ru/post/958003/


All Articles