简单

语言特性始终保持少且足够的水平,不走语言融合的道路,简单的设计哲学是 Go 生产力的源泉

  1. 仅有 25 个关键字,主流编程语言最少
  2. 内置 GC,降低开发人员内存管理的心智负担
  3. 首字母大小写决定可见性,无需通过额外关键字修饰
  4. 变量初始为类型零值,避免以随机值作为初值的问题
  5. 内置数组边界检查,极大减少越界访问带来的安全隐患
  6. 内置并发支持,简化并发程序设计
  7. 内置接口类型,为组合的设计哲学奠定基础
  8. 原生提供完善的工具链,开箱即用

显式

Go - 程序员应该明确知道在做什么;C - 信任程序员

  1. Go 不允许不同类型的变量进行混合计算,也不会进行隐式自动转换
  2. Go 采用基于值比较的错误处理方案
    • 函数或方法的错误会通过 return 语句显式地返回,并且调用者通常不能忽略对返回的错误的处理

组合

组合是构建 Go 程序骨架的主要方式,可以大幅度降低程序元素间的耦合,提高程序的可扩展性灵活性

  1. 在 Go 中,找不到经典的 OOP 语法元素类型体系继承机制,Go 推崇的是组合的设计哲学
  2. 提供正交的语法元素,以供后续组合使用
    • 之间相对独立,没有子包的概念
    • 没有类型层次体系,各类型之间互相独立,没有子类型的概念
    • 每个类型都可以有自己的方法集合,类型定义方法实现正交独立
    • 实现某个接口时,无需像 Java 那样采用特殊的关键字修饰 - Duck Typing
  3. 组合 - 将各个没有关联的孤岛以最恰当的方式建立关联,并形成一个整体

类型嵌入为类型提供了垂直扩展的能力,而接口水平组合的关键

垂直组合 - Inherit

本质上是能力继承,采用嵌入方式定义的新类型继承了嵌入类型的能力

Type Embedding - Go 为了支撑组合的设计,提供了类型嵌入(Type Embedding) - 语法糖
通过 Type Embedding,将已经实现的功能嵌入到新类型中,以快速满足新类型的功能需求

  1. 被嵌入的类型和新类型之间没有任何关系
  2. 通过新类型调用方法时,方法匹配主要取决于方法名字,而不是类型
    • 通过 Type Embedding,快速让一个新类型复用其他类型已经实现的能力,实现功能的垂直扩展
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type Mutex struct {
}

func (receiver *Mutex) Lock() {
fmt.Println("Mutex Lock")
}

func (receiver *Mutex) UnLock() {
fmt.Println("Mutex UnLock")
}

type Pool struct {
Mutex
}

func main() {
pool := Pool{}
pool.Lock() // Mutex Lock
pool.UnLock() // Mutex UnLock
}

水平组合 - Delegate

本质是能力委托 - 通过嵌入接口类型的方式实现接口行为的聚合

1
2
3
4
5
6
7
8
9
10
11
12
13
// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
Reader
Writer
}

type Reader interface {
Read(p []byte) (n int, err error)
}

type Writer interface {
Write(p []byte) (n int, err error)
}

Go 接口是一个创新设计

  1. 在 Go 中,接口只是方法集合,与实现之间的关系无需通过显式关键字修饰
  2. 让程序内部各部分之间的耦合降低到最低,也是连接程序各部分之间的纽带

其他水平组合的模式 - 通过接受接口类型参数普通函数进行组合

1
2
3
4
5
6
7
type Reader interface {
Read(p []byte) (n int, err error)
}

func ReadAll(r io.Reader) ([]byte, error) {
return io.ReadAll(r)
}

并发

  1. Go 放弃了基于操作系统线程的并发模型(Java),而采用了用户层轻量级线程,即 goroutine
  2. goroutine 占用的资源非常少,Go Runtime 默认为每个 goroutine 分配的栈空间2KB
  3. goroutine 调度的切换也不用陷入操作系统内核完成,代价很低
  4. 在语言层面内置了辅助并发设计的原语 - channel + select
    • 通过 channel 传递消息或者实现同步
    • 通过 select 实现多路 channel 的并发控制
  5. 并发和组合的哲学是一脉相承的,并发是一个更大的组合的概念
    • goroutines 各自执行特定的工作,通过 channel + select 将 goroutines 组合连接起来
    • 并发的存在鼓励程序员在程序设计时进行独立计算分解

面向工程

  1. 重新设计编译单元和目标文件格式,实现 Go 源码快速构建
    • 让大工程的构建时间缩短到类似动态语言的交互式解析的编译速度
  2. 如果源文件导入它不使用的包,则程序无法编译,进而充分保证 Go 程序的依赖树精确
    • 保证在构建程序时不会编译额外的代码,从而最大限度地缩短编译时间
  3. 去除包的循环依赖
    • 循环依赖会在大规模的代码中引发问题,因为它们要求编译器同时处理更大的源文件集,这会减慢增量构建
  4. 包路径唯一的,而包名不唯一
    • 导入路径必须唯一标识要导入的包
    • 名称只是包的使用者如何引用其内容的约定
  5. 故意不支持默认函数参数
    • 如果函数拥有太多的参数,会降低代码的清晰度和可读性
  6. 增加类型别名(Type alias),支持大规模代码库的重构
  7. Go 在标准库中提供了各类高质量性能优良的功能包
  8. Go 提供了完善的工具链
    • 编译构建、代码格式化(gofmt)、包依赖管理、静态代码检查
    • 单元测试、文档生成与查看、性能剖析、语言服务器、运行时程序跟踪