最近学习了一下go语言,这个语言的设计非常有趣,很多简洁精巧的构思,学习起来也很舒服,摆脱了CPP语言那些麻烦的特性,同时。并没有产生过多的混淆。并带来了效书写效率的提升,虽然Vibe

Coding的时代并不需要手写代码了。这篇文章希望仅从语法层面列举一些我认为比较不同的特点

  • 零值机制,尽管无法避免空指针问题,但是省去了很多初始化的麻烦
  • 类型名后置,并且将声明和类型定义区分开了,声明方法有(var s string 和 s := “”),并且常量提供了无类型初始化,防止了溢出。
  • 文件组织很有秩序,现代化;一个Go语言编写的程序对应一个或多个以.go为文件后缀名的源文件。每个源文件中以包的声明语句开始,说明该源文件是属于哪个包。包声明语句之后是import语句导入依赖的其它包,然后是包一级的类型、变量、常量、函数的声明语句,包一级的各种类型的声明语句的顺序无关紧要(译注:函数内部的名字则必须先声明之后才能使用)。
  • go中没有类,但是通过方法,将变量包等都以一等公民对待,都可以实现自己的方法。不需要设置访问修饰符例如public private。通过首字母大小写就可以实现封装
要点 含义
包一级 type 通常定义在顶层,让整个包共享该类型
大写导出 Go 用首字母大小写控制可见性,不需要写 public/private 关键字
小写私有 小写开头的类型/字段只能在当前包内使用,是封装的基础
  • 标准库对web开发封装很好
  • for循环的写法也很方便(for initialization; condition; post方法和for _, arg := range os.Args[1:])
  • go通过自动将脱离作用域的局部变量分配到堆上,而不是栈上,实现了对局部变量的返回。尽管局部变量的作用域还是函数内,但是生命周期被gc延长至不再使用时才回收。构成了闭包机制
  • 对于包级变量(package-level variables)来说,Go 的编译器不严格按照代码的书写顺序来初始化包级变量,而是根据变量之间的依赖关系(dependency)自动分析并决定初始化顺序。
  • 匿名嵌套结构体的方法会自动提升
  • 取消了函数声明的大部分复杂操作。不支持默认参数值,不支持函数重载,不支持按参数名传参。同时支持多返回值。甚至可以被看做第一类值,拥有类型,可以被赋值给其他变量,传递给函数,从函数返回。设置了defer关键字确保在函数返回前执行,减少了许多防御编程。当panic异常发生时,程序会中断运行,并立即执行在该goroutine(可以先理解成线程,在第8章会详细介绍)中被延迟的函数(defer 机制)。随后,程序崩溃并输出日志信息
  • go的错误机制包括:
模式 示例 说明
立即返回 if err != nil { return err } 最标准写法
添加上下文 return fmt.Errorf("process %d: %w", id, err) 保留原始错误
忽略错误 _ = f.Close() 必须显式用 _ 忽略
哨兵错误 var ErrNotFound = errors.New("not found") 包级公开错误供 errors.Is 判断
异常
panic(err)
panic 用于 bug / 不可恢复状态(如代码逻辑错误、初始化失败),不用于 业务错误(如文件不存在、网络超时)。
通常不对panic处理,但是又是可以尝试恢复
  • 使用鸭子类型,来定义接口,无需implement,实现了参数多态,并且极易实现依赖倒置。但是在接口值处理上有一些需要注意的地方
  • 原生协程机制,使用go方便调用,另外提供无缓存同步channel,和有缓存异步channel很容易在协程之间传递数据。
  • 另外,go提供了context结构体,可以通过设置KV对来传值,但是由于只能在子节点查询父节点值,而不能在父节点查询子节点值。另外,不同协程储存储的值可能会导致重复,所以应该慎用.context 使用起来非常方便。源码里对外提供了一个创建根节点 context 的函数:
1
func Background() Context

background 是一个空的 context, 它不能被取消,没有值,也没有超时时间。

有了根节点 context,又提供了四个函数创建子节点 context:

1
2
3
4
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context

context 会在函数传递间传递。只需要在适当的时间调用 cancel 函数向 goroutines 发出取消信号或者调用 Value 函数取出 context 中的值。

  1. 不要将 Context 塞到结构体里。直接将 Context 类型作为函数的第一参数,而且一般都命名为 ctx。
  2. 不要向函数传入一个 nil 的 context,如果你实在不知道传什么,标准库给你准备好了一个 context:todo。
  3. 不要把本应该作为函数参数的类型塞到 context 中,context 存储的应该是一些共同的数据。例如:登陆的 session、cookie 等。
  4. 同一个 context 可能会被传递到多个 goroutine,别担心,context 是并发安全的

本站由 Edison.Chen 创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。