在Go语言中的Fibonacci闭包实现

huangapple go评论85阅读模式
英文:

Fibonacci closure in go

问题

我正在遵循官方网站上的Go教程,并被要求编写一个斐波那契数列生成器。以下是代码:

package main

import "fmt"

// fibonacci是一个返回函数的函数,该函数返回一个int。
func fibonacci() func() int {
    first := 0
    second := 0
    return func() int {
        if first == 0 {
            first = 1
            second = 1
            return 0
        } else {
            current := first
            firstc := second
            second = first + second
            first = firstc
            return current
        }
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

这段代码是有效的。然而,我认为它很丑陋,我相信一定有更好的解决方案。我一直在考虑将其发布到代码审查中,但由于我正在寻求更好的方法,所以我认为这是发布的正确地方。

有没有更好的编写这段代码的方法?

任务要求如下:

实现一个斐波那契函数,该函数返回一个函数(闭包),该函数返回连续的斐波那契数。

英文:

I am following the go tour on their official website and I have been asked to write a Fibonacci generator. Here it is:

 package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
    first := 0
    second := 0
    return func() int{
        if(first == 0) {
         first = 1
         second = 1
         return 0
        }else {
            current := first   
            firstc := second
            second = first + second
            first = firstc
            return current
        }
                 
        
       
    }
}

func main() {
    f := fibonacci()
    for i := 0; i &lt; 10; i++ {
        fmt.Println(f())
    }
}

It works. However I consider it very ugly and I'm sure there has to be a better solution. I have been thinking about posting this on the code-review however since I'm asking for a better approach I thought this is the right place to post it.

Is there a better way to write this code?

Here is the task:

> Implement a fibonacci function that returns a function (a closure) that returns successive fibonacci numbers.

答案1

得分: 89

我最喜欢的实现斐波那契数列迭代的方法是使用first作为fi-1second作为fi。斐波那契数列的递推公式如下:

fi+1 = fi + fi-1

但是在代码中,下一轮迭代时我们会递增i。因此,实际上我们在做以下操作:

f下一个i = f当前i + f当前i-1

以及

f下一个i-1 = f当前i

我喜欢在代码中这样实现:

first, second = second, first + second

first = second 部分对应于更新 f下一个i-1 = f当前i,而 second = first + second 部分对应于更新 f下一个i = f当前i + f当前i-1

然后我们只需要返回旧的 first 值,所以在更新之前我们将其存储在一个临时变量中。总体而言,我们得到以下代码:

// fibonacci 返回一个函数,每次调用该函数时返回下一个斐波那契数
func fibonacci() func() int {
    first, second := 0, 1
    return func() int {
        ret := first
        first, second = second, first+second
        return ret
    }
}

Go Playground 上可以看到它的运行效果。

英文:

My favorite clean way to implement iterating through the Fibonacci numbers is to use first as f<sub>i - 1</sub>, and second as f<sub>i</sub>. The Fibonacci equation states that:

f<sub>i + 1</sub> = f<sub>i</sub> + f<sub>i - 1</sub>

Except when we write this in code, in the next round we're incrementing i. So we're effectively doing:

f<sub>next i</sub> = f<sub>current i</sub> + f<sub>current i - 1</sub>

and

f<sub>next i - 1</sub> = f<sub>current i</sub>

The way I like to implement this in code is:

first, second = second, first + second

The first = second part corresponds to updating f<sub>next i - 1</sub> = f<sub>current i</sub>, and the second = first + second part corresponds to updating f<sub>next i</sub> = f<sub>current i</sub> + f<sub>current i - 1</sub>.

Then all we have left to do is return the old value of first, so we'll store it in a temp variable out of the way before doing the update. In total, we get:

// fibonacci returns a function that returns
// successive fibonacci numbers from each
// successive call
func fibonacci() func() int {
	first, second := 0, 1
	return func() int {
		ret := first
		first, second = second, first+second
		return ret
	}
}

See it in action on the Go Playground.

答案2

得分: 9

一个小技巧

package main

import "fmt"

// fibonacci 是一个返回
// 返回一个 int 的函数。
func fibonacci() func() int {
	a := 0
	b := 1
	return func() int {
		a, b = b, a+b
		return b-a
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
英文:

A small trick

package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	a := 0
	b := 1
	return func() int {
		a, b = b, a+b
		return b-a
	}
}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(f())
	}
}

答案3

得分: 8

另一种方法

func fibonacci() func() int {
    n1, n := -1, 1
    return func() int {
        n1, n = n, n1+n
        return n
    }
}

Go Playground

英文:

Another approach

func fibonacci() func() int {
    n1, n := -1, 1
    return func() int {
        n1, n = n, n1+n
        return n
    }
}

The Go Playground

答案4

得分: 5

我会使用多重赋值,缩短标识符的长度,并删除那个 if 语句:

func fibonacci() func() int {
    var a, b int
    b = 1
    return func() int {
        ret := a
        a, b = b, a+b
        return ret
    }
}
英文:

I would make use of multiple assignment, reduce the length of identifiers, and remove that if statment:

func fibonacci() func() int {
	var a, b int
	b = 1
	return func() int {
		ret := a
		a, b = b, a+b
		return ret
	}
}

答案5

得分: 4

这是我的做法。

func fibonacci() func() int {
    var s = []int{0,1}

    return func() int{
        ret := s[0]
        s[0],s[1] = s[1],s[0]+s[1]
        return ret
    }
}
英文:

This is how I have done.

func fibonacci() func() int {
    var s = []int{0,1}

    return func() int{
        ret := s[0]
        s[0],s[1] = s[1],s[0]+s[1]
        return ret
    }
}

答案6

得分: 3

这是我建议的一种方法,通过将每个数字存储在一个Map中。

package main

import "fmt"

// fibonacci是一个返回一个int的函数。
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610,
// 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025,
// 121393, 196418, 317811, 514229
func fibonacci() func() int {
    numbers := make(map[int]int)
    n := 0
    return func() int {
        if n == 0 {
            numbers[n] = 0
            n++
            return 0
        }
        if n == 1 {
            numbers[n] = 1
            n++
            return 1
        }
        number := numbers[n-1] + numbers[n-2]
        numbers[n] = number
        n++
        return number
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 30; i++ {
        fmt.Println(f())
    }
}

希望对你有帮助!

英文:

Here is also my suggestion by storing each number in a Map.

package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610,
// 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025,
// 121393, 196418, 317811, 514229
func fibonacci() func() int {
	numbers := make(map[int]int)
	n := 0
	return func() int {
		if n == 0 {
			numbers[n] = 0
			n++
			return 0
		}
		if n == 1 {
			numbers[n] = 1
			n++
			return 1
		}
		number := numbers[n-1] + numbers[n-2]
		numbers[n] = number
		n++
		return number
	}}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 30; i++ {
		fmt.Println(f())
	}
}

答案7

得分: 1

除了已经提供的答案,你还可以使用defer函数来实现:

package main

import "fmt"

// fibonacci是一个返回int的函数。
func fibonacci() func() int {
	secondLast := 0
	last := 1
	return func() int {
		defer func() {
			secondLast, last = last, secondLast+last
		}()
		return secondLast
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

但我认为jwoodalls的答案是最高效的。

编辑:但是,如果你想使用无符号整数(展示你的架构可以计算多少个斐波那契数),你需要使用变量保存返回值或者使用defer函数的方法。

package main

import "fmt"

// fibonacci是一个返回uint的函数。
func fibonacci() func() uint {
	var secondLast uint
	var last uint = 1
	return func() uint {
		defer func() {
			secondLast, last = last, secondLast+last
		}()
		return secondLast
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

或者更好的方法是使用float64!

package main

import "fmt"

// fibonacci是一个返回float64的函数。
func fibonacci() func() float64 {
	var secondLast float64
	var last float64 = 1
	return func() float64 {
		defer func() {
			secondLast, last = last, secondLast+last
		}()
		return secondLast
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
英文:

Besides the already provided answers you could also use a defer function for it:

package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	secondLast := 0
	last := 1
	return func() int {
		defer func() {
			secondLast, last = last, secondLast+last
		}()
		return secondLast
	}
}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(f())
	}
}

Go Playground

But i guess jwoodalls answers is the most performant one.

Edit: But if you wanna use unsigned integers (to show off how many fibonacci numbers you can compute on your architecture 在Go语言中的Fibonacci闭包实现 ) you would have to use either the approach with the variable holding the return value or the defer function.

package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an uint.
func fibonacci() func() uint {
	var secondLast uint
	var last uint = 1
	return func() uint {
		defer func() {
			secondLast, last = last, secondLast + last
		}()
		return secondLast
	}
}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(f())
	}
}

Go Playground

EditEdit: Or even better: use float64!!!

package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an float64.
func fibonacci() func() float64 {
	var secondLast float64
	var last float64 = 1
	return func() float64 {
		defer func() {
			secondLast, last = last, secondLast+last
		}()
		return secondLast
	}
}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(f())
	}
}

Go Playground

答案8

得分: 1

你可以使用这种方法...简单易懂,虽然与之前的答案没有太大区别。

package main

import "fmt"

// fibonacci 是一个返回一个返回 int 的函数。
func fibonacci() func() int {
	f1 := 0
	f2 := 1
	return func() int {
		temp := f1 + f2
		temp2 := f1
		f1 = f2
		f2 = temp
		return temp2
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
英文:

Or u may use this approach...simple and understandable, though not very different from the previous answers.

package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	f1 := 0
	f2 := 1
	return func() int {
		temp := f1+f2
		temp2 := f1
		f1 = f2
		f2 = temp
		return temp2
	}
}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(f())
	}
}

答案9

得分: 0

package main

import "fmt"

// fibonacci 是一个返回一个返回 int 的函数。
func fibonacci() func() int {
    a, b, sum := 1, 1, 0
    return func() int {
        a, b = b, sum
        sum = a + b
        return b
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

这是一个使用闭包实现斐波那契数列的 Go 代码。在 main 函数中,我们创建了一个 fibonacci 函数,它返回一个返回 int 的函数。这个返回的函数使用了三个变量 absum,并且在每次调用时更新这些变量的值,最后返回 b。在 main 函数中,我们通过调用 fibonacci 函数创建了一个函数 f,然后使用循环调用 f 并打印结果,实现了输出斐波那契数列的前 10 个数。

英文:
package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	a, b, sum := 1, 1, 0
	return func() int {
		a,b = b,sum
		sum = a + b
		return b
	}
}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(f())
	}
}

答案10

得分: 0

我也在这个练习中遇到了一些问题,感谢大家提供的答案。我想分享一下,如果你继续进行Go之旅并进入并发部分,还有另一种使用通道实现的方法,可以在并发课程4中找到。

lesson 4的代码片段:

package main

import (
	"fmt"
)

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	close(c)
}

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
	for i := range c {
		fmt.Println(i)
	}
}

英文:

I had a bit of trouble with this exercise as well, thank you to everyone for these answers. Thought I would also share that if you continue the go tour and make it to the concurrency section, there is another way to implement this using channels in concurrency lesson 4.

Code snippet from lesson 4:

package main

import (
	&quot;fmt&quot;
)

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i &lt; n; i++ {
		c &lt;- x
		x, y = y, x+y
	}
	close(c)
}

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
	for i := range c {
		fmt.Println(i)
	}
}

答案11

得分: 0

尝试使用以下解决方案,如果你希望你的答案以零开始。

func fibonacci() func() int {
    a, b := 0, 1
    upd := func() { a, b = b, a+b }
    return func() int {
        defer upd()
        return a
    }
}

func main() {
    fib := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(fib())
    }
}

这段代码实现了一个斐波那契数列生成器,每次调用 fib() 函数时,会返回下一个斐波那契数。在 main() 函数中,我们创建了一个 fibonacci() 函数的实例,并循环调用 fib() 函数来打印前10个斐波那契数。

英文:

Try this solution if you want that your answer start with zero.

func fibonacci() func() int {
	a, b := 0, 1
	upd := func() { a, b = b, a+b }
	return func() int {
		defer upd()
		return a
	}
}

func main() {
	fib := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(fib())
	}
}

答案12

得分: 0

package main

import "fmt"

// fibonacci 是一个返回函数的函数,该函数返回一个 int。
func fibonacci() func() int {
	r := []int{0, 0, 1}
	return func() int {
		r = []int{r[1], r[2], r[1] + r[2]}
		return r[0]
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

这是一个使用Go语言编写的斐波那契数列的程序。它定义了一个名为fibonacci的函数,该函数返回一个返回int类型的函数。在main函数中,我们调用fibonacci函数并将返回的函数赋值给变量f,然后使用循环打印出前10个斐波那契数列的值。

英文:
package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	r := []int{0,0,1}
	return func() int{
		r = []int{r[1],r[2],r[1]+r[2]}
		return r[0]
	}
}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(f())
	}
}

答案13

得分: 0

我能够使用这篇帖子中关于Go语言中正确递归语法的提示,实现了一个递归闭包解决方案:

package main

import "fmt"

// fibonacci是一个返回int类型的函数。
func fibonacci() func(int) int {
  var recur func(int) int
  recur = func(x int) int {
    switch x {
      case 0:
        return 0
      case 1:
        return 1
      default:
        return (recur(x - 1) + recur(x - 2))
    }
  }
  return recur
}

func main() {
  f := fibonacci()
  for i := 0; i < 10; i++ {
    fmt.Println(f(i))
  }
}

你可以在这里找到关于在Go语言中正确使用递归的语法的帖子:https://stackoverflow.com/a/34194763/1592607

英文:

I was able to implement a recursive closure solution using hints from this post on the correct recursive syntax in go:
https://stackoverflow.com/a/34194763/1592607

package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func(int) int {
  var recur func(int) int
  recur = func(x int) int {
    switch x {
      case 0:
        return 0
      case 1:
        return 1
      default:
        return (recur(x - 1) + recur(x - 2))
    }
  }
  return recur
}

func main() {
  f := fibonacci()
  for i := 0; i &lt; 10; i++ {
    fmt.Println(f(i))
  }
}

答案14

得分: -1

package main

import "fmt"

// fibonacci 是一个返回一个返回 int 的函数。
func fibonacci() func() int {
	first := 0
	second := 0
	return func() int {
		if second == 0 {
			second = 1
		} else if first == 0 {
			first = 1
		} else {
			first, second = second, first+second
		}
		return second
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

这是一个使用闭包实现斐波那契数列的 Go 代码。在 main 函数中,我们创建了一个 fibonacci 函数,它返回一个返回 int 的函数。这个返回的函数每次被调用时,都会返回斐波那契数列中的下一个数。在 main 函数中,我们通过循环调用这个返回的函数,并打印出结果。

英文:
package main

import &quot;fmt&quot;

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
	first:=0
	second:=0
	return func() int{
		if second == 0 {
			second = 1
		} else if first == 0 {
			first = 1
		} else {
			first, second = second, first + second
		}
		return second
	}
}

func main() {
	f := fibonacci()
	for i := 0; i &lt; 10; i++ {
		fmt.Println(f())
	}
}

huangapple
  • 本文由 发表于 2014年8月26日 01:37:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/25491370.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定