Go语言学习笔记(1)Map和Channel

最近在学习Go语言,我在这里把遇到的一些坑还有难点记录下。

Map中的坑

map没法直接用struct

下面的代码会报错

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

import "fmt"

var m = map[string]struct{x, y int} {
	"foo": {2, 3},
}

func main() {
	m["foo"].x = 4 // cannot assign to m["foo"].x
	fmt.Println(m)
}

解决的办法是用指针

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

import fmt

var m = map[string]*struct{x, y int} {
foo: {2, 3},
}

func main() {
m[foo].x = 4
fmt.Println(m[foo].x)
}

Channel

定义

1
2
messages := make(chan string, 2)
done := make(chan bool)

###发送接收数据

1
2
ch <- v    // 发送v到channel ch.
v := <-ch  // 从ch中接收数据,并赋值给v

默认情况的channel是阻塞式的,可以把channel理解为水管,阻塞式channel是一根小水管,一有东西进来,他就会堵住,除非channel里面的东西被取出。

也可以有非阻塞的channel,这样的channel可以存放多个数据,只要在make的时候用第二个参数执行channel的长度就可以了。非阻塞式channel只有当写入数据达到channel长度的时候才会阻塞。

用range遍历非阻塞channel

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
    "fmt"
)

func fibonacci(n int, c chan int) {
    x, y := 1, 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)
    }
}

语法跟一般的for range非常类似。但是要注意你很可能需要用close关闭channel,否则会一直循环下去。

判断channel是否关闭

从channel中读取数据的时候,指定两个变量,第一个变量存放channel中的数据,第二个变量用来表示channel是否关闭

1
v, ok := <-ch

select

我们上面介绍的都是只有一个channel的情况,那么如果存在多个channel的时候,我们该如何操作呢,Go里面提供了一个关键字select,通过select可以监听channel上的数据流动。

select默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,select是随机的选择一个执行的。

select也可以是非阻塞的

如果在select里面提供default选项,那么如果所有其他选项的channel都没数据的时候,会执行default选项,也就不会阻塞了。

updatedupdated2020-07-232020-07-23