在 Go 语言基础学习过程中,确实如 Google 介绍文章写得那样,Go 践行了一系列改进特性,下面就列举一些发现的特性。
杀手锏——并发优化:
- 用 goroutine 实现多线程的功能,充分利用多核 CPU,用户态、容量小、切换代价低、自动阻塞调度、调用简单 go …
- 用 channel 实现阻塞、同步、数据传输
- 用 select 实现 fan-in 等待、非阻塞通信
- 提供 stack trace、deadlock 检测、data race 检测,以便发现错误
逻辑清晰:
- 每个变量、函数的定义都很明确,没有太多隐含的类型,这样使人更容易理解,同时也更容易编写语言工具
- 循环精简为只有 for 一个关键字,避免很多重复的关键字功能,避免了过于灵活的代码,代码可读性加强
- switch 语句默认每个 case 自带 break,没有了隐含的多个 case 连续执行的时序
- 创造性的用 defer+panic+recover 的方式实现了 try+catch+finally 的功能,并且更容易理解
- Go 的函数不再允许默认参数
- 赋值表达式本身不能作为表达式进行赋值,这样自增运算就不可以作为赋值表达式了(x++ <=> x = x + 1)
- 虽然上面的修改可能导致代码量的增加,但是对于长期要维护的代码,可维护性更好
编译快速:
- import 后没有使用的情况会编译不过,这样就避免了 C++中 include 后不敢删除的情况,大型代码更容易维护
- 没有声明直接定义,这样编译链接速度更快
一些方便的语法或机制
- map[string]int 的使用类似 unordered_map<string,map>,在不存在元素的情况下可以 m[key]++,省去了很多判断语句
- 所有元素都是初始化过的或为 nil,不会出现随机内容的情况
- 函数可以直接当做函数对象传递和使用,并且可以直接捕获外部变量,类似 λ 函数,也可以形成闭包(可以写一个漂亮的 fibonacci 函数)
- 用指针 method 方式实现类似 C++的 class,其实就是自己为 C++的 this 指针命名
- 通过 interface 类型实现了隐含的接口,很好的实现了解耦合,避免提前设计引起的过度设计,可以使系统升级更平滑
- 函数的局部变量的地址可以返回,因为某对象到底在堆还是栈上创建,会由编译器进行自动判断,最后由垃圾回收处理
- 空接口(interface{})相当于一个特殊的变量,同时存储着指向一个对象的指针及这个对象的类型。
便利的工具
- VSCode 可以很方便的安装插件,提供自动提示、格式化等 IDE 功能
- 如果代码中存在循环包引用,要先用
go build
发现一下,否则会造成解析工具死循环
- 如果代码中存在循环包引用,要先用
- gofmt 称为默认的格式化工具,每次保存时会自动进行代码格式整理,只要按照编码规范注意语法使用即可,格式会自动调整
与 C++相比一些不方便的地方
- 不支持泛型,没有 STL 这样好用的库,缺少一些常用的容器等。(可以找开源代码或自己写)
- PS(20200324):官方团队有一个开源工具
go2go
支持 Generic(相当于 C++的 Template) Contract(相当于 C++的 Class Template) 功能,可是实现常用算法,但是属于尝试阶段,不支持 select、which、channel 写入等
- PS(20200324):官方团队有一个开源工具
- 很多现成的 C/C++的库没法直接使用了,需要研究一下调用方法
- 缺少三目运算符
PS: Concurrency(并发)与 Parallelism(并行计算)的区别
- 并发是通过切换时间片来实现”同时”运行,并行计算是利用多核 CPU 实现多线程运行
- Go 是 Concrrency 而不是 Parallelism
- goroutine 本质上就是 Go 语言官方内置的线程池
- goroutine 的使用原则是:Don’t communicate by sharing memory; share memory by communicating.
- 充分利用 chan 和 goroutine 就可以达到同步、通信(大容量对象用指针或 slice),逻辑更清晰,无锁(显式的 mutex)更高效