这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记
函数式编程
函数式编程 vs 函数指针
- 函数是一等公民:参数,变量,返回值都可以是函数
- 高阶函数
- 函数 -> 闭包
Go语言是通用语言
“正统”函数式编程(了解)
- 不可变性:不能有状态,只有常量和函数
- 函数只能有一个参数
函数与闭包
函数体内包含局部变量和自由变量
Go语言闭包的应用
为函数实现接口**
package main
import (
"bufio"
"fmt"
"io"
"strings"
)
func fibonacci() intGen {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
type intGen func() int
func (g intGen) Read(p []byte) (n int, err error) {
next := g()
if next > 100000 {
return 0, io.EOF
}
s := fmt.Sprintf("%d\n", next)
//TODO: incorrect if p is too small!
return strings.NewReader(s).Read(p)
}
func printFileContents(reader io.Reader) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
func main() {
f := fibonacci()
printFileContents(f)
}
- 更为自然,不需要修饰如何访问自由变量
- 没有Lambda表达式,但是有匿名函数
错误处理
defer调用
- 确保在函数结束时调用
- 参数在defer语句时计算
- defer列表为后进先出Stack
出错处理
func writeFile(filename string) {
file, err := os.OpenFile(
filename, os.O_EXCL|os.O_CREATE, 0666)
if err != nil {
if PathError, ok := err.(*os.PathError); !ok {
panic(err)
} else {
fmt.Println("%s, %s, %s\n", PathError.Op, PathError.Path, PathError.Err)
}
return
}
}
自己生成错误
err = errors.New("This is a custom error")
测试
Debugging sucks; Testing Rocks!
Goroutine
协程Coroutine
- 轻量级“线程”
- 非抢占式多任务处理,由协程主动交出控制权
- 编译器/解释器/虚拟机层面的多任务
- 多个协程可能在一个或多个线程上运行
- 子程序是协程的一个特例 -Donnald Knuth
- 任何函数只需加上
go就能送给调度器运行 - 不需要在定义时区分是否为异步函数
- 调度器在合适的点进行切换,尽管是非抢占式
- 使用
-race来检测数据访问冲突
eg:Python中的协程使用yield关键字实现协程,Python3.5 加入了async def对协程原生支持
Goroutine可能的切换点
- I/O ,select
- 函数调用(有时)
- channel
- runtime.Gosched()
- 等待锁
- 只是参考,不能保证切换,不能保证在其他地方不切换
Channel
- channel
- buffered channel
- range
- 理论基础:Communication Sequential Process(CSP)
不用通过共享内存来通信;通过通信来共享内存
Channel close : 发送方去close
接收方判断方法 1. ok 2.range语法
实例1:系统自带WaitGroup等待多人
package main
import (
"fmt"
"sync"
)
func doWork(id int, c chan int, w worker) {
for n := range w.in {
fmt.Printf("Worker %d received %c\n", id, n)
w.done()
}
}
type worker struct {
in chan int
done func()
}
func createWorker(id int, wg *sync.WaitGroup) worker {
w := worker{
in: make(chan int),
done: func() {
wg.Done()
},
}
go doWork(id, w.in, w)
return w
}
func chanDemo() {
var workers [10]worker
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
workers[i] = createWorker(i, &wg)
}
wg.Add(20)
for i, worker := range workers {
worker.in <- 'a' + i
}
for i, worker := range workers {
worker.in <- 'A' + i
}
wg.Wait()
}
func main() {
chanDemo()
}