递归函数
简单来讲就是自己调用自己,达到临界值,就不调用了。
我们先来看一个简单的递归。
典型的例子:斐波那契数列
什么是斐波那契数列?
从第三项开始,每一项都等于前两项之和
1,1,2,3,5,8,13…这样的数列就是斐波那契数列
1+1=2
1+2=3
2+3=5
…
也就是这样写就是一个递归函数
定义一个fb的函数返回值是调用自己 当n=0时停止递归。
闭包
现在开始通过例子来说明闭包:
func incr() func() int {
var x int
return func() int {
x++
return x
}
}
调用这个函数会返回一个函数变量。
i := incr()
:通过把这个函数变量赋值给 i
,i
就成为了一个闭包。
所以 i
保存着对 x
的引用,可以想象 i 中有着一个指针指向 x 或 i 中有 x 的地址。
由于 i
有着指向 x
的指针,所以可以修改 x
,且保持着状态:
println(i()) // 1
println(i()) // 2
println(i()) // 3
也就是说,x
逃逸了,它的生命周期没有随着它的作用域结束而结束。
但是这段代码却不会递增:
println(incr()()) // 1
println(incr()()) // 1
println(incr()()) // 1
这是因为这里调用了三次 incr()
,返回了三个闭包,这三个闭包引用着三个不同的 x
,它们的状态是各自独立的。
闭包引用
现在开始通过例子来说明由闭包引用产生的问题:
x := 1
f := func() {
println(x)
}
x = 2
x = 3
f() // 3
因为闭包对外层词法域变量是引用的,所以这段代码会输出 3。
可以想象 f
中保存着 x
的地址,它使用 x
时会直接解引用,所以 x
的值改变了会导致 f
解引用得到的值也会改变。
但是,这段代码却会输出 1:
x := 1
func() {
println(x) // 1
}()
x = 2
x = 3
把它转换成这样的形式就容易理解了:
复制代码
x := 1
f := func() {
println(x)
}
f() // 1
x = 2
x = 3
这是因为 f
调用时就已经解引用取值了,这之后的修改就与它无关了。
不过如果再次调用 f
还是会输出 3,这也再一次证明了 f
中保存着 x
的地址。
可以通过在闭包内外打印所引用变量的地址来证明:
x := 1
func() {
println(&x) // 0xc0000de790
}()
println(&x) // 0xc0000de790
可以看到引用的是同一个地址。