原文
https://tour.golang.org/welcome/1
指针
Go 具有指针。 指针保存了变量的内存地址。
类型 *T 是指向 T 类型值的指针。其零值为 nil 。
var p *int
& 操作符会生成一个指向其操作数的指针。
i := 42
p = &i
fmt.Println(*p)
*p = 21
这也就是通常所说的“间接引用”或“重定向”。
与 C 不同,Go 没有指针运算。
package main
import (
"fmt"
)
func main() {
a, b := 12, 33
p := &a
fmt.Printf("p = %v, *p = %v\n", p, *p)
*p = *p * 2
fmt.Printf("p = %v, *p = %v\n", p, *p)
p = &b
fmt.Printf("p = %v, *p = %v\n", p, *p)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
输出:
p = 0xc082004258, *p = 12
p = 0xc082004258, *p = 24
p = 0xc082004280, *p = 33
结构体
一个结构体( struct )就是一个字段的集合。
(而 type 声明就是定义类型的。)
package main
import (
"fmt"
)
type People struct {
name string
age int
}
func main() {
fmt.Println(People{"Afra", 22})
}
输出:
{Afra 22}
结构体字段
结构体字段使用点号来访问。
package main
import (
"fmt"
)
type People struct {
name string
age int
}
func main() {
me := People{"Afra", 22}
fmt.Printf("name = %v, age = %v\n", me.name, me.age)
}
输出:
name = Afra, age = 22
结构体指针
结构体字段可以通过结构体指针来访问。
如果我们有一个指向结构体的指针 p ,那么可以通过 (*p).X 来访问其字段 X 。 不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X 就可以。
package main
import (
"fmt"
)
type People struct {
name string
age int
}
func main() {
me := People{"Afra", 22}
p := &me
fmt.Printf("name = %v, age = %v\n", p.name, p.age)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
输出:
name = Afra, age = 22
结构体文法
结构体文法通过直接列出字段的值来新分配一个结构体。
使用 Name:
语法可以仅列出部分字段。(字段名的顺序无关。)
特殊的前缀 &
返回一个指向结构体的指针。
package main
import (
"fmt"
)
type People struct {
name string
age int
}
var (
a = People{"Afra", 22}
b = People{age: 22}
c = People{name: "Victor"}
d = People{}
e = &People{"Victor", 87}
)
func main() {
fmt.Println(a, b, c, d, e)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
输出:
{Afra 22} { 22} {Victor 0} { 0} &{Victor 87}
数组
类型 [n]T 表示拥有 n 个 T 类型的值的数组。
表达式
var a [10]int
会将变量 a 声明为拥有有 10 个整数的数组。
数组的长度是其类型的一部分,因此数组不能改变大小。 这看起来是个限制,不过没关系, Go 提供了更加便利的方式来使用数组。
package main
import (
"fmt"
)
func main() {
var a [2]string
a[0] = "Afra55"
a[1] = "Victor"
fmt.Println(a[0], a[1])
fmt.Println(a)
b := [6]int{1, 2, 4, 5, 6, 6}
fmt.Println(b)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
输出:
Afra55 Victor
[Afra55 Victor]
[1 2 4 5 6 6]
切片
每个数组的大小都是固定的。 而切片则为数组元素提供动态大小的、灵活的视角。 在实践中,切片比数组更常用。
类型 []T 表示一个元素类型为 T 的切片。
以下表达式为数组 a 的前五个元素创建了一个切片。
a[0:5]
package main
import (
"fmt"
)
func main() {
source := [6]int{1, 2, 3, 5, 4}
var s []int = source[2:6]
fmt.Println(s)
}
输出:
[3 5 4 0]
切片就像数组的引用
切片并不存储任何数据, 它只是描述了底层数组中的一段。
更改切片的元素会修改其底层数组中对应的元素。
与它共享底层数组的切片都会观测到这些修改。
package main
import (
"fmt"
)
func main() {
source := [6]int{1, 2, 3, 5, 4}
var s []int = source[2:6]
fmt.Println(s)
source[5] = 7
fmt.Println(s)
s[0] = 88
fmt.Println(source)
}
输出:
[3 5 4 0]
[3 5 4 7]
[1 2 88 5 4 7]
切片文法
切片文法类似于没有长度的数组文法。
这是一个数组文法:
[3]bool{true, true, false}
下面这样则会创建一个和上面相同的数组,然后构建一个引用了它的切片:
[]bool{true, true, false}
package main
import (
"fmt"
)
func main() {
a := []int{12, 5, 3, 6, 8, 6}
fmt.Println(a)
b := []struct {
age int
name string
}{
{1, "xx"}, {2, "xxx"}, {3, "xxxx"},
}
fmt.Println(b)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
输出:
[12 5 3 6 8 6]
[{1 xx} {2 xxx} {3 xxxx}]
切片的默认行为
在进行切片时,你可以利用它的默认行为来忽略上下界。
切片下界的默认值为 0 ,上界则是该切片的长度。
对于数组:
var a [10]int
来说,以下切片是等价的:
a[0:10]
a[:10]
a[0:]
a[:]
package main
import (
"fmt"
)
func main() {
a := []int{12, 5, 3, 6, 8, 6}
a = a[1:6]
fmt.Println(a)
a = a[:3]
fmt.Println(a)
a = a[2:]
fmt.Println(a)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
输出:
[5 3 6 8 6]
[5 3 6]
[6]
切片的长度与容量
切片拥有 长度 和 容量 。
切片的长度就是它所包含的元素个数。
切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。
切片 s 的长度和容量可通过表达式 len(s)
和 cap(s)
来获取。
package main
import (
"fmt"
)
func main() {
a := []int{12, 5, 3, 6, 8, 6}
a = a[:0]
printSlice(a)
a = a[:3]
printSlice(a)
a = a[2:]
printSlice(a)
}
func printSlice(s []int) {
fmt.Printf("len = %d, cap = %d, value = %v\n", len(s), cap(s), s)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
输出:
len = 0, cap = 6, value = []
len = 3, cap = 6, value = [12 5 3]
len = 1, cap = 4, value = [3]
由上面可见,不管切片怎么变化,他的长度和容量都和他存储的 第一个元素 有关。
nil 切片
切片的零值是 nil 。
nil 切片的长度和容量为 0 且没有底层数组。
package main
import "fmt"
func main() {
var s []int
fmt.Println(s, len(s), cap(s))
if s == nil {
fmt.Println("nil!")
}
}
输出:
[] 0 0
nil!
用 make 创建切片
切片可以用内建函数 make 来创建,这也是你创建动态数组的方式。
make 函数会分配一个元素为零值的数组并返回一个引用了它的切片:
a := make([]int, 5)
要指定它的容量,需向 make 传入第三个参数:
b := make([]int, 0, 5)
b = b[:cap(b)]
b = b[1:]
package main
import (
"fmt"
)
func main() {
a := make([]int, 6)
printSlice("a", a)
b := make([]int, 0, 5)
printSlice("b", b)
c := make([]int, 3, 5)
printSlice("c", c)
d := b[:2]
printSlice("d", d)
e := d[2:5]
printSlice("e", e)
}
func printSlice(flag string, s []int) {
fmt.Printf("%s, len = %d, cap = %d, value = %v\n", flag, len(s), cap(s), s)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
输出:
a, len = 6, cap = 6, value = [0 0 0 0 0 0]
b, len = 0, cap = 5, value = []
c, len = 3, cap = 5, value = [0 0 0]
d, len = 2, cap = 5, value = [0 0]
e, len = 3, cap = 3, value = [0 0 0]
切片的切片
切片可包含任何类型,甚至包括其它的切片。
package main
import (
"fmt"
"strings"
)
func main() {
a := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
printSlice("s", a)
a[0][0] = "x"
a[2][2] = "x"
a[1][2] = "x"
a[0][2] = "x"
printSlice("s", a)
for i := 0; i < len(a); i++ {
fmt.Println(strings.Join(a[i], " "))
}
}
func printSlice(flag string, s [][]string) {
fmt.Printf("%s, len = %d, cap = %d, value = %v\n", flag, len(s), cap(s), s)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
输出:
s, len = 3, cap = 3, value = [[_ _ _] [_ _ _] [_ _ _]]
s, len = 3, cap = 3, value = [[x _ x] [_ _ x] [_ _ x]]
x _ x
_ _ x
_ _ x
向切片追加元素
为切片追加新的元素是种常用的操作,为此 Go 提供了内建的 append 函数。 内建函数的文档对此函数有详细的介绍。
func append(s []T, vs …T) []T
append 的第一个参数 s 是一个元素类型为 T 的切片, 其余类型为 T 的值将会追加到该切片的末尾。
append 的结果是一个包含原切片所有元素加上新添加元素的切片。
当 s 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。 返回的切片会指向这个新分配的数组。
(要了解关于切片的更多内容,请阅读文章Go 切片:用法和本质。)
package main
import (
"fmt"
)
func main() {
a := []int{1, 2, 3, 4, 5}
printSlice(a)
a = append(a, 8)
printSlice(a)
a = append(a, 8, 9, 10, 11, 12)
printSlice(a)
var b []int
printSlice(b)
b = append(b, 0)
printSlice(b)
b = append(b, 1)
printSlice(b)
b = append(b, 2)
printSlice(b)
b = append(b, 3, 4, 5)
printSlice(b)
}
func printSlice(s []int) {
fmt.Printf("len = %d, cap = %d, value = %v\n", len(s), cap(s), s)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
输出:
len = 5, cap = 5, value = [1 2 3 4 5]
len = 6, cap = 10, value = [1 2 3 4 5 8]
len = 11, cap = 20, value = [1 2 3 4 5 8 8 9 10 11 12]
len = 0, cap = 0, value = []
len = 1, cap = 1, value = [0]
len = 2, cap = 2, value = [0 1]
len = 3, cap = 4, value = [0 1 2]
len = 6, cap = 8, value = [0 1 2 3 4 5]
由上面的输出结果可看,向切片追加元素,新切片的容量以原切片的容量为基数倍增,直到空间能够容乃所有元素。
Range
for 循环的 range 形式可遍历切片或映射。
当使用 for 循环遍历切片时,每次迭代都会返回两个值。 第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。
package main
import (
"fmt"
)
var result = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
printSlice(result)
for i, v := range result {
fmt.Printf("i = %d, value = %d\n", i, v)
}
}
func printSlice(s []int) {
fmt.Printf("len = %d, cap = %d, value = %v\n", len(s), cap(s), s)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
输出:
len = 8, cap = 8, value = [1 2 4 8 16 32 64 128]
i = 0, value = 1
i = 1, value = 2
i = 2, value = 4
i = 3, value = 8
i = 4, value = 16
i = 5, value = 32
i = 6, value = 64
i = 7, value = 128
可以将下标或值赋予 _ 来忽略它。
若你只需要索引,去掉 , value 的部分即可。
package main
import (
"fmt"
)
func main() {
result := make([]int, 10)
printSlice(result)
fmt.Println("\n只获取索引:")
for i := range result {
result[i] = 1 << uint(i)
fmt.Printf("i = %d, value = %d\n", i, result[i])
}
fmt.Println("\n只获取 value:")
for _, v := range result {
fmt.Printf("value = %d\n", v)
}
}
func printSlice(s []int) {
fmt.Printf("len = %d, cap = %d, value = %v\n", len(s), cap(s), s)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
输出:
len = 10, cap = 10, value = [0 0 0 0 0 0 0 0 0 0]
只获取索引:
i = 0, value = 1
i = 1, value = 2
i = 2, value = 4
i = 3, value = 8
i = 4, value = 16
i = 5, value = 32
i = 6, value = 64
i = 7, value = 128
i = 8, value = 256
i = 9, value = 512
只获取 value:
value = 1
value = 2
value = 4
value = 8
value = 16
value = 32
value = 64
value = 128
value = 256
value = 512
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
映射
映射将键映射到值。
映射的零值为 nil 。nil
映射既没有键,也不能添加键。
make 函数会返回给定类型的映射,并将其初始化备用。
package main
import (
"fmt"
)
type People struct {
age int
name string
}
var m map[string]People
func main() {
m = make(map[string]People)
fmt.Println(m)
m["Afra55"] = People{
22, "Victor",
}
fmt.Println(m)
fmt.Println(m["Afra55"])
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
输出:
map[]
map[Afra55:{22 Victor}]
{22 Victor}
映射的文法
映射的文法与结构体相似,不过必须有键名。
package main
import (
"fmt"
)
type People struct {
age int
name string
}
var m = map[string]People{
"Victor": People{12, "LaBabaLa"},
"Afra55": People{221, "FFFFFFF"},
}
func main() {
fmt.Println(m)
m["Afra55"] = People{
22, "XXXXXX",
}
fmt.Println(m)
fmt.Println(m["Afra55"])
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
输出:
map[Victor:{12 LaBabaLa} Afra55:{221 FFFFFFF}]
map[Afra55:{22 XXXXXX} Victor:{12 LaBabaLa}]
{22 XXXXXX}
可以在文法的元素中省略顶级类型名。
var m = map[string]People{
"Victor": {12, "LaBabaLa"},
"Afra55": {221, "FFFFFFF"},
}
修改映射
在映射 m 中插入或修改元素:
m[key] = elem
获取元素:
elem = m[key]
删除元素:
delete(m, key)
通过双赋值检测某个键是否存在:
elem, ok = m[key]
若 key 在 m 中, ok 为 true ;否则, ok 为 false 。
若 key 不在映射中,那么 elem 是该映射元素类型的零值。
同样的,当从 映射 中读取某个不存在的键时,结果是 映射 的元素类型的零值。
注 :若 elem 或 ok 还未声明,你可以使用短变量声明:
elem, ok := m[key]
package main
import (
"fmt"
)
type People struct {
age int
name string
}
var m = map[string]People{
"Victor": {12, "LaBabaLa"},
"Afra55": {221, "FFFFFFF"},
}
func main() {
m["Lazyer"] = People{
32, "Old man",
}
fmt.Println(m)
m["Afra55"] = People{
22, "XXXXXX",
}
fmt.Println(m)
checkExist("Afra55")
delete(m, "Afra55")
checkExist("Afra55")
}
func checkExist(key string) {
elem, ok := m[key]
if ok {
fmt.Printf("%s is %d\n", key, elem)
} else {
fmt.Printf("%s not exist, the value is %v\n", key, elem)
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
输出:
map[Lazyer:{32 Old man} Victor:{12 LaBabaLa} Afra55:{221 FFFFFFF}]
map[Victor:{12 LaBabaLa} Afra55:{22 XXXXXX} Lazyer:{32 Old man}]
Afra55 is {22 %!d(string=XXXXXX)}
Afra55 not exist, the value is {0 }
函数值
函数也是值。它们可以像其它值一样传递。
函数值可以用作函数的参数或返回值。
package main
import (
"fmt"
"math"
)
func main() {
toSqrt := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(toSqrt(12, 5))
fmt.Println(autoSqrt(toSqrt))
fmt.Println(autoSqrt(math.Pow))
}
func autoSqrt(fn func(x, y float64) float64) float64 {
return fn(4, 3)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
输出:
13
5
64
函数的闭包
Go 函数可以是一个闭包。闭包是一个函数值,它引用了其函数体之外的变量。 该函数可以访问并赋予其引用的变量的值,换句话说,该函数被“绑定”在了这些变量上。
例如,函数 adder 返回一个闭包。每个闭包都被绑定在其各自的 sum 变量上。
package main
import (
"fmt"
)
func main() {
a := adder()
fmt.Println(a)
for i := 0; i < 10; i++ {
fmt.Println(a(i))
}
b := adder()
fmt.Println(b)
for i := 0; i < 10; i++ {
fmt.Println(b(i * -1))
}
}
func adder() func(int) int {
sum := 0
fmt.Println("sum is init: ", sum)
return func(x int) int {
sum += x
return sum
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
输出:
sum is init: 0
0x401660
0
1
3
6
10
15
21
28
36
45
sum is init: 0
0x401660
0
-1
-3
-6
-10
-15
-21
-28
-36
-45
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
练习:斐波纳契闭包
让我们用函数做些好玩的事情。
实现一个 fibonacci 函数,它返回一个函数(闭包), 该闭包返回一个斐波纳契数列 (0, 1, 1, 2, 3, 5, ...)
。
package main
import "fmt"
func fibonacci() func() int {
a, b:=0, 1
return func() int{
b, a = b+a, b
return a
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
输出:
1
1
2
3
5
8
13
21
34
55