I am new to Go language and got confused with the following code
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
previous := 0
current := 1
return func () int{
current = current+previous
previous = current-previous
return current
}
}
func main() {
f := fibonacci
for i := 0; i < 10; i++ {
fmt.Println(f()())
}
}
This code is supposed to print out the Fibonacci Sequence (first 10), but only print out 10 times 1.
but if I change the code to:
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
Then it is working fine. The output is the Fibonacci sequence.
Could any one help me explain this?
Thanks
fibonacci() creates a new fibonacci generator function. fibonacci()() does the same, and then calls it once, returns the result and discards the generator, never to be used again. If you call that in a loop, it'll just keep creating new generators and only using their first value.
If you want more than just the first value, you need to do exactly what you did in your second example. Store the generator itself in a variable and then call the same generator multiple times.
This has to do with how variables are encapsulated in closures after returning the closure.
Consider the following example (live code on play):
func newClosure() func() {
i := 0
fmt.Println("newClosure with &i=", &i)
return func() {
fmt.Println(i, &i)
i++
}
}
func main() {
a := newClosure()
a()
a()
a()
b := newClosure()
b()
a()
}
Running this code will yield something like the following output. I annotated
which line comes from which statement:
newClosure with &i= 0xc010000000 // a := newClosure()
0 0xc010000000 // a()
1 0xc010000000 // a()
2 0xc010000000 // a()
newClosure with &i= 0xc010000008 // b := newClosure()
0 0xc010000008 // b()
3 0xc010000000 // a()
In the example, the closure returned by newClosure encapsulates the local variable i.
This corresponds to current and the like in your code. You can see that a and b
have different instances of i, or else the call b() would've printed 3 instead.
You can also see that the i variables have different addresses. (The variable is already
on the heap as go does not have a separate stack memory, so using it in the closure is
no problem at all.)
So, by generating a new closure you're automatically creating a new context for the
closure and the local variables are not shared between the closures. This is the reason
why creating a new closure in the loop does not get you further.
The equivalent in for your code in terms of this example would be:
for i:=0; i < 10; i++ {
newClosure()()
}
And you've already seen by the output that this will not work.
func fibonacci() func() int return a function literal (closure) that returns an int representing the last generated number in the list.
The first main() method
f := fibonacci
for i := 0; i < 10; i++ {
fmt.Println(f()())
}
f is the generator function, every iteration in the loop invoke f()() that generates a new closure with a new envirement ( previous := 0, current := 1), so , the second invocation returns current which is always equal to 1.
The second main() method
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
f is the closure (not the generator) with an initial envirement ( previous := 0, current := 1), every iteration in the loop invoke f() witch returns current and modify the envirement, so whith the next call, previous will be 1 and current 2.
Related
The following code causes a compilation error:
main.go:8:9: p declared and not used
package main
func main() {
pointers := make([]*int, 5)
a := 1 // create an int
for _, p := range pointers {
p = &a
}
}
Writing to p doesn't count as using it?
P is only scoped to the loop block and essentially gets a copy of a pointers slice element every time it goes through the loop. This would work though:
package main
import "fmt"
func main() {
pointers := make([]*int, 5)
a := 1 // create an int
for i := range pointers {
pointers[i] = &a
}
fmt.Println(pointers)
}
Playground
I am playing around with Go and am trying to implement a fibonacci function that returns a closure that returns fibonacci numbers. The problem can be found in the go tool tour. Here is a closure implementation that uses a regular (non-naked) return:
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
a := 0
b := 1
return func() int {
t := a + b
a = b
b = t
return b
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
The function correctly returns the following:
1
2
3
5
8
13
21
34
55
89
I tried writing the fibonacci function differently by trying to use a naked return within the closure function, but it produces an error:
./compile20.go:9:7: b declared and not used
Here is the code that generates the error
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
a := 0
b := 1
return func() (b int) {
t := a + b
a = b
b = t
return
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
Anybody know how the variable b is not being used? b is obviously used in the first line of the closure function (t := a + b).
Variables defined in the return segment shadow the variable with the same name in the outer scope. Inside your returned function, b refers to the one defined in the return value.
You can remove the first declaration (and initialization) of b and the program passes the check, although the logic is not right.
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
a := 0
b := 1 // declare a variable b and initialize with 1
return func() (b int) { // declare a variable b with default initialization
t := a + b // b refers to the variable defined in the return value
a = b
b = t
return
}
}
package main
import (
"fmt"
)
func main(){
f,val,val1:=fibonacci()
fmt.Println(val,val1)
for i:=0;i<=10;i++ {
fmt.Println(f(i),val,val1)
}
_,val,val1=fibonacci()
fmt.Println(val,val1)
}
func fibonacci()(func(n int)int,int,int){
var val int
var val1 int
f:=func(n int)int{
if n==0||n==1{
val,val1=1,1
}else{
val,val1=val+val1,val
}
return val
}
fmt.Println("fibonacci val =",val,"val1 =",val1)
return f,val,val1
}
Here is my code on sloving fibonacci without using recursion when I
read about lambda function/closure. And the Go Documentary says a
closure will capture some external state. My understanding is the
closure will keep a copy of state of the function which it is
declared. These states are just copies whatever I do on them won't
modify the original, is that so?
from your test code here: https://play.golang.org/p/pajT2bAIe2
your fibonacci function is working out the nth numbers in the sequence provided it's called in an incremental fashion as you are doing. but the values you return from the initial call to fibonacci are not pointers (or references) to those integer values they are just the values of those integers at that time, think of them as being copied out of the function, try using integer pointers instead like this: https://play.golang.org/p/-vLja7Fpsq
package main
import (
"fmt"
)
func main() {
f, val, val1 := fibonacci()
fmt.Println(val, val1)
for i := 0; i <= 10; i++ {
fmt.Println(f(i), *val, *val1) //dereference the pointer to get its value at the current time
}
_, val, val1 = fibonacci()
fmt.Println(*val, *val1)
}
func fibonacci() (func(n int) int, *int, *int) {
var val int
var val1 int
f := func(n int) int {
if n == 0 || n == 1 {
val, val1 = 1, 1
} else {
val, val1 = val+val1, val
}
return val
}
fmt.Println("fibonacci val =", val, "val1 =", val1)
return f, &val, &val1 // return pointers to the closured values instead of just the values
}
Although you have accepted the above answer i'm giving another explanation. The reason why you receive the last value of the loop operation has to do with the Go's lexical scoping. The for loop introduces a new lexical block in which the value is referenced by it's memory address, so by pointer and not by it's value. In order to get the value, you have to de-reference.
Each time the for loop makes an iteration the value processed is pointing to the same memory address. All the function values created by this loop "capture" and share the same variable - and addressable storage location, not it's value at that particular moment. Thus when the last iteration is finished, the variable holds the value from the final step.
A much better approach for these kind of operations would be to use goroutines, because in these cases you are not communicating through sharing the same memory address, but you are sharing the memory through communication.
Here is a more elegant solution using goroutine:
package main
import (
"fmt"
)
func fibonacci(ch chan interface{}, quit chan struct{}) {
x, y := 1, 1
for {
select {
case ch <- x:
x, y = y, x+y
fmt.Println(x , y)
case <-quit:
fmt.Println("Quiting...")
return
}
}
}
func main() {
ch := make(chan interface{})
quit := make(chan struct{})
go func() {
for i := 0; i < 10; i++ {
<-ch
}
quit <- struct{}{}
}()
fibonacci(ch, quit)
}
https://play.golang.org/p/oPQgXWyV9u
I am trying to parallelize an operation in golang and save the results in a manner that I can iterate over to sum up afterwords.
I have managed to set up the parameters so that no deadlock occurs, and I have confirmed that the operations are working and being saved correctly within the function. When I iterate over the Slice of my struct and try and sum up the results of the operation, they all remain 0. I have tried passing by reference, with pointers, and with channels (causes deadlock).
I have only found this example for help: https://golang.org/doc/effective_go.html#parallel. But this seems outdated now, as Vector as been deprecated? I also have not found any references to the way this function (in the example) was constructed (with the func (u Vector) before the name). I tried replacing this with a Slice but got compile time errors.
Any help would be very appreciated. Here is the key parts of my code:
type job struct {
a int
b int
result *big.Int
}
func choose(jobs []Job, c chan int) {
temp := new(big.Int)
for _,job := range jobs {
job.result = //perform operation on job.a and job.b
//fmt.Println(job.result)
}
c <- 1
}
func main() {
num := 100 //can be very large (why we need big.Int)
n := num
k := 0
const numCPU = 6 //runtime.NumCPU
count := new(big.Int)
// create a 2d slice of jobs, one for each core
jobs := make([][]Job, numCPU)
for (float64(k) <= math.Ceil(float64(num / 2))) {
// add one job to each core, alternating so that
// job set is similar in difficulty
for i := 0; i < numCPU; i++ {
if !(float64(k) <= math.Ceil(float64(num / 2))) {
break
}
jobs[i] = append(jobs[i], Job{n, k, new(big.Int)})
n -= 1
k += 1
}
}
c := make(chan int, numCPU)
for i := 0; i < numCPU; i++ {
go choose(jobs[i], c)
}
// drain the channel
for i := 0; i < numCPU; i++ {
<-c
}
// computations are done
for i := range jobs {
for _,job := range jobs[i] {
//fmt.Println(job.result)
count.Add(count, job.result)
}
}
fmt.Println(count)
}
Here is the code running on the go playground https://play.golang.org/p/X5IYaG36U-
As long as the []Job slice is only modified by one goroutine at a time, there's no reason you can't modify the job in place.
for i, job := range jobs {
jobs[i].result = temp.Binomial(int64(job.a), int64(job.b))
}
https://play.golang.org/p/CcEGsa1fLh
You should also use a WaitGroup, rather than rely on counting tokens in a channel yourself.
The following code:
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
first, second := 0, 1
return func() int {
// return next fibonacci number here.
first, second = second, first+second
return first
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
returns 10 numbers of the fibonacci sequence. What's confusing to me is why is works. It seems like the values first and second are somehow saved in memory, since each time the code is executed, a new fibonacci number in sequence with the previous one is returned. I thought that functions lost their remembered variables when they were done executing. What is going on here?
first, and second are variables in the fibonacci() func, that were 'closed over' by the returned func() int that was returned from fibonacci().
So they are in the closure associated with f, so f has access to those variables as long as it exists.
See this Go Tour slide (and the ones around it) for some explanation of Go closures.