Go语言编程

Table of Contents

1. 顺序编程

  • 有限的类型推导
    • var k = "hello" or k := "hello"
    • 不会对函数返回值类型进行推导
  • 不定参数 `args …int` 可以认为是数组切片类型 `args []int`
  • range用来遍历数组, 切片, 以及字典.
  • 数组和切片
    • 切片是数组的封装,为数组操作提供更多接口
    • 切片更像是数组指针,保存对底层数组的引用
    • len表示切片当前长度,cap表示切片最大容量
  • 指针 仅限于引用,不可以运算,智能解引用((&s).X 和 s.X)
  • 映射 `_, ok ` m[key]= 判断是否存在; delete 删除映射
  • 取消while, 只保留for.
    • for <init>; <loop>; <pred> { … }
    • for <loop> { … }
    • for { … }
  • 多重赋值, 多值返回, 匿名函数与闭包
  • 错误处理 error
  • RAII解决方案 defer
  • 异常传播 panic + recover
    • panic(value). 触发异常并携带value
    • if r := recover() ; r != nil 捕获可能的异常并处理.
  • new用来分配对象内存,make只用于创建切片,映射和信道并且不返回指针
  • 每个源文件内部 `init()` 函数会在初始化时候调用

2. 类型系统

  • 值语义 vs. 引用语义
    • 大部分cases都是值语义
    • 看起来像引用语义的有
      1. 数组切片
      2. map
      3. channel
      4. interface
    • 这些"引用语义"类型内部实现都是维护指针
  • 方法和函数差别不大 `func (v Vertex) Abs()` 和 `func Abs(v Vertex)`
  • 方法 `func (a A)` 自动会实现 `func (a *A)`
    • 智能解引用
    • 通常使用指针作为接受者,好处有下面两点:
    • 可以修改结构里面的字段
    • 如果是大型结构体可以避免拷贝
  • 初始化 new(A), A{a:1, b:2}, A{1,2}
  • 匿名组合
    • 类型和接口都可以通过匿名组合来实现继承
    • 隐式地实现接口
  • 非侵入式接口
    • 对象实例可以赋值给接口
    • 接口之间可以赋值
    • 在内部接口值可以看做包含值和具体类型的元组(value, type).
  • 类型/接口查询
    • 值是否实现某个接口 `v.(IReader)` 或是什么类型 `v.(type)`
    • t, ok := i.(T) 如果成功,ok=True, t则为对应类型T
    • i.(type) 取得底层类型

3. 并发编程

  • goroutine go协程 see libtask
    • 使用CPU数量 runtime.GOMAXPROCS()
    • 主动yield runtime.GoSched()
  • 并发通信
    • 基于消息传递 channel `chan type`
      • 单向写入channel `chan<- type`
      • 单向读出channel `<-chan type`
      • 通过make(chan type [,bufsize])来创建. 信道可以是有缓冲的
    • 基于内存共享 sync.* 同步机制
  • select 有效轮询各个channels状态
    • select本身没有提供timeout机制
    • workaround办法是启动另外一个检测超时的goroutine

4. 工程管理

  • 目录组织 # src/pkg/bin
  • 集成工具 # go pkg/perf/…
  • 代码风格 # go fmt
  • 远程import支持 # go get
  • 内置单元测试和性能测试 # testing