Contents
  1. 1. Map
    1. 1.1. map literals
    2. 1.2. Map操作
    3. 1.3. Map练习
  2. 2. 函数value
  3. 3. 函数闭包
    1. 3.1. 闭包练习:Fibonacci数列

Map

Map就是Key-value对。map必须make后才能使用,nilmap是无法赋值的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}

map literals

map literalsstruct literals是类似的,不过key是必须的。

1
2
3
4
5
6
7
8
9
10
11
12
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}

如果顶层类型只是一个类型名,可以将它从literal元素们中省略。

1
2
3
4
var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}

Map操作

新建或更新map项

1
m[key] = elem

取值

1
elem = m[key]

删除元素

1
delete(m, key)

检测key是否存在

1
2
elem, ok = m[key]
elem, ok := m[key] //短定义

如果存在,则返回 值+true,否则返回对应类型的0值和false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
import "fmt"
func main() {
m := make(map[string]int)
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok)
}

Map练习

实现一个WordCount,统计一个string中每个单词的频度,这个练习可以本地做,也可以在golang.org的交互式网页做,它提供一个结果校验功能。
提示,可以使用strings包中的Fields方法
https://tour.golang.org/moretypes/20
以下是我的答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import (
"golang.org/x/tour/wc"
"strings"
)
func WordCount(s string) map[string]int {
r := make(map[string]int)
for _,w := range strings.Fields(s){
r[w] += 1
}
return r
}
func main() {
wc.Test(WordCount)
}

结果

1
2
3
4
5
6
7
8
9
10
11
12
PASS
f("I am learning Go!") =
map[string]int{"I":1, "am":1, "learning":1, "Go!":1}
PASS
f("The quick brown fox jumped over the lazy dog.") =
map[string]int{"fox":1, "jumped":1, "quick":1, "brown":1, "over":1, "the":1, "lazy":1, "dog.":1, "The":1}
PASS
f("I ate a donut. Then I ate another donut.") =
map[string]int{"Then":1, "another":1, "I":2, "ate":2, "a":1, "donut.":2}
PASS
f("A man a plan a canal panama.") =
map[string]int{"A":1, "man":1, "a":2, "plan":1, "canal":1, "panama.":1}

可见这种0缺省值的设定还是很好用的,可以让程序简练。

函数value

在Go中函数也是值,可以用作函数参数与返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}

以上述例子中,compute函数的参数是一个2个参数和返回值都是float64的函数。变量hypot的值是一个函数。

函数闭包

Go函数可以是闭包。所谓闭包是一个引用了外部变量的函数值,这个函数可以存取和赋值给变量。这种意义上该函数被绑定到变量。
下面的例子中,adder函数返回一个闭包。每个闭包被绑定到它自有的sum变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println( pos(i), neg(-2*i),)
}
}

运行:

1
2
3
4
5
6
7
8
9
10
0 0
1 -2
3 -6
6 -12
10 -20
15 -30
21 -42
28 -56
36 -72
45 -90

闭包练习:Fibonacci数列

题目就不用解释了,菲波那契数列大家都很熟悉,由0,1开始,之后每个元素都是前二者的和。0, 1, 1, 2, 3, 5, …

我的答案(参考之后的结果,一开始是懵逼的,居然不带参数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
import "fmt"
func fibonacci() func()int{
x,y:=0,1
return func()(r int) {
r=x
x,y = y,x+y
return
}
}
func main(){
f:=fibonacci()
for i:=0;i<10;i++ {
fmt.Println(f())
}
}

运行:

1
2
3
4
5
6
7
8
9
10
0
1
1
2
3
5
8
13
21
34

很有趣是不是?首先f:=fibnacci() 定义了function value,这是闭包的前提。按我的猜测,此时为f分配了内存空间,包括其中的变量xy,所以在f的生命周期内,x,y是一直存在的,因此当匿名函数一直操作其外部的x,y时,其变化一真累积,这也是fibonacci()不用传入参数的原因。最后fibonacci应该从0开始返回,这里也用到了一个Go特有的return方式来实现。

Contents
  1. 1. Map
    1. 1.1. map literals
    2. 1.2. Map操作
    3. 1.3. Map练习
  2. 2. 函数value
  3. 3. 函数闭包
    1. 3.1. 闭包练习:Fibonacci数列