Go基础学习 初步使用的总结

在 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 写入等
  • 很多现成的 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)更高效

参考: https://tour.golang.org