函数式
函数式编程是一种编程范式,基于lambda运算,强调数据的映射。
haskell和lisp之类的函数式编程出来已经挺久了,但是一直没有得到特别广泛的应用,主要还是性能问题。
不过函数式编程的很多概念值得学习,因为它们确实抽象程度比较高,实际编码和搞研究的时候都可以得到比较高的开发效率。
高阶函数
高阶函数其实是参数和返回值可以是函数的函数。对应的,一阶函数就是直接对数据进行操作的函数。
map/reduce/filter/sort 就是典型的高阶函数。
高阶函数的概念在实际编程中还是很有用的,比较可以多一类抽象。
C语言也可以通过指针的方式支持高阶函数,C库的qsort函数就是用函数指针参数。
go更是把函数当成了第一公民。
闭包
闭包的概念一句话解释:“闭包是一个包含属性变量的高阶函数”。相当于用函数模拟面向对象里面类的概念。
实际工程中完全可以把闭包当成一个轻量的类来是用。
协程
程序开发过程中,会遇到各种各样的并发和异步操作,常见的异步操作是线程和进程。
go的goroutine和channel最近比较火,就是因为它让并发编程变容易了很多。goroutine基于多线程实现,比多线程要轻。
那么协程是什么的,协程并不是真正的并发,只是看起来像并发。它实现这样一种效果:“两个或多个函数交替执行代码”。
交替执行的两个函数可能还是在一个线程下执行的。
那这样的伪并发有什么实际价值呢?它还是有一些实际用途的,比如python中的generator;两个函数相互引用数据(相互递归);
实现状态机的时候也比较自然:A状态下执行函数f,B状态下执行函数Y,C状态下执行函数Z,然后每个函数执行完改变状态就是直接跳到另一个函数执行。
协程这样区别于常规的执行流,可以用于实现异常处理。
async/await
在C#和javascript中一直有这样一种语法,以前一直不明白其含义,仔细研究之后,发现这其实就是协程的一种写法。
await f() await g() 与 f() g()有什么差异呢?差异在于await后面的f, g是“同时”执行的,而不是等f执行完再去执行g!
试想,f 和 g 用于两条tcp连接的收包,程序就可以在f连接没有数据包的时候去处理g的报文,这提高了整体的收包效率。
async/await 经常被用在非阻塞IO方面。实际上,coroutine加非阻塞io,类似于在用户态实现了一个select系统调用。
回顾以前写C非阻塞收发包的代码,一个select监听了多个文件描述符,内核可以出发有数据的文件描述符触发特定代码执行。这跟多个await监听多个fd效果相同。
即使不用async/await, C语言实现的coroutine库,在异步非阻塞收发包的时候也是有用的,可以把收取部分字节写成一个coroutine,没有包的时候就yield。
先去干其他的事情。这样可以实现类似select的效果。
异常处理
异常处理,类似C++的try-catch-finally,在程序发生panic的时候,可以打断原来的控制流,执行一个另外的程序,否则继续执行。
在处理自定义异常的时候,这样做看起来没有多大必要,因为可以通过代码检查判断返回。
但是有些低级的异常,比如除以0这样的异常,直接造成了系统的错误指令,catch异常看起来还挺自然的。
go在后来的版本中也引入了异常处理机制,panic recover,panic的时候会执行defer语句,但go并不鼓励使用recover捕获异常。
最好的方式是避免错误本身的出现。