在GO中,您可以定义返回函数的函数。让我们调用第一个函数A
和返回的一个B
。函数b被匿名定义为以下return func() returnType {}
,并且可以引用函数A
的变量。如果匿名函数确实来自函数A
引用变量,我们说B
在其引用以形成a 闭合的所有非局部变量上关闭。让我们以生成奇数的函数的示例(从书籍中获取的示例引入GO构建可靠,可扩展的程序):
func main() {
nextOdd := MakeOddGenerator()
fmt.Println(nextOdd()) // Prints 1
fmt.Println(nextOdd()) // Prints 3
}
MakeOddGenerator() func() uint {
i := uint(1)
return func() (res uint) {
res = i
i = 2 * i + 1
return
}
}
在上面的示例中,变量i
在函数nextOdd
的不同调用之间保持其值。但是,它如何帮助我们计算斐波那契序列的元素?
好吧,计算斐波那契序列元素的最常用方法是使用递归,事实上,递归似乎是自然而然的。那么,让我们看一下斐波那契的序列是什么?这是一个正整数的序列(简单地说,元素列表),称为 f 或 fib 定义为以下方式:
- 纤维(0)= 0
- 纤维(1)= 1
- 对于n大于1,fib(n)= fib(n -1) + fib(n -2)
这是斐波那契序列的前15个元素:0、1 1、2、3、5、8、13、34、34、55、89、144、233、377、610。
最后一行Fib(n) = Fib(n - 1) + Fib(n - 2)
是使我们对使用递归进行计算的直觉。因此,让我们实现一种递归算法来计算斐波那契序列的第n个元素:
func FibonacciRec(x uint) uint {
if x == 0 {
return 0
} else if x == 1 {
return 1
} else {
return FibonacciRec(x-1) + FibonacciRec(x-2)
}
}
如果您尝试此功能,它可能与x的少量值正常工作,但是当我使用X = 50尝试时,在我的计算机上(核心i7 11th Gen,在WSL2中运行Ubuntu 16GB RAM),我得到了这些计算FIB的结果(50):
我不认识您,但是1分钟是“ Just” Fib(50)的长时间。当您考虑它时,这是有道理的。让我们分析fib的呼叫堆栈(n)。如果n与0或1不同,则至少需要两个其他功能来获取答案,对于每个函数,如果不是0或1,则您还需要至少两个其他功能呼叫等等。
现在,从这个“堆栈”中,您还可能会注意到某些值是计算两次的(或者如果您以更深的深度绘制堆栈),则用当前算法进行单词,我们无法重复使用在我们的情况下,已经计算出的值,例如FIB(N-2)和FIB(N-3)。
让我们尝试使用GO中的封闭来解决此问题。首先,我们需要一个返回函数的函数:
func FibonacciDyna() func(y int) int {
return func(y int) int {
}
}
接下来,我们需要“记住”序列的先前计算的元素,因为我们将数组(或在GO术语中切片)变量添加到Englobing函数:
func FibonacciDyna() func(y int) int {
fib := []int{0,1}
return func(y int) int {
}
}
请注意,我们添加了斐波那契序列的前两个元素。然后,我们需要考虑多种情况,但是在此之前,我们还必须注意序列的nth元素与数组的第n个元素的对应:
func FibonacciDyna() func(y int) int {
fib := []int{0,1}
return func(y int) int {
// negative numbers are not supported
if y < 0 {
panic("negative number not supported")
}
// We already computed the value.
if y < int(len(fib)) {
return fib[y]
}
// We have the two previous value Fib(n-1) and
// Fib(n-2) needed for computation.
if y-2 >= 0 && y < len(fib) {
// Store the newly computed value
fib = append(fib, fib[y-1]+fib[y-2])
return fib[y]
}
// We don't have one or both of the two previous
// value needed for computation.
// We then compute and store all the missing values.
for i:= len(fib); i<= y; i++ {
fib = append(fib, fib[y-1]+fib[y-2])
}
return fib[y]
}
}
您甚至可以添加一些测试:
func TestFibonacciOf0ShouldReturn0(t *testing.T) {
x := 0
want := 0
getFibDyn := FibonacciDynamic()
have := getFibDyn(x)
if want != have {
t.Fatalf(`FibonacciDynamic(%d) = %d, want equal for %d`, x, have, want)
}
}
func TestFibonacciOf1ShouldReturn1(t *testing.T) {
x := 1
want := 1
getFibDyn := FibonacciDynamic()
have := getFibDyn(x)
if want != have {
t.Fatalf(`FibonacciDynamic(%d) = %d, want equal for %d`, x, have, want)
}
}
func TestFibonacciOf10ShouldReturn55(t *testing.T) {
x := 10
want := 55
getFibDyn := FibonacciDynamic()
have := getFibDyn(x)
if want != have {
t.Fatalf(`FibonacciDynamic(%d) = %d, want equal for %d`, x, have, want)
}
}
现在让我们运行:
好多!
就是这样,让我知道您在下面的评论中的想法!
您可能会找到源代码here