Go语言学习笔记
Go语言特征
静态强类型、编译型、并发型、并具有垃圾回收功能的编程语言
用 Goroutine 运行所有的一切,包括 main.main 入口函数,是一种虚拟线程。Go语言运行时会参与调度 goroutine,并将 goroutine 合理地分配到每个 CPU 中,最大限度地使用 CPU 性能。
用channel,实现 CSP 模型。将并发单元间的数据耦合拆解开来,是一种内置的数据结构,可以让用户在不同的 goroutine 之间同步发送具有类型的消息。这让编程模型更倾向于在 goroutine 之间发送消息,而不是让多个 goroutine 争夺同一个数据的使用权
tcmalloc做内存分配器,使用Cache做无锁分配
语法总结
声明变量:var name type (var 变量名 变量类型)
简短格式定义变量:变量名字 := 表达式
定义变量,同时显式初始化。
匿名变量是一个下划线"_"
不占用内存空间,不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用
任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算
全局变量声明必须以 var 关键字开头,如果想要在外部包中使用全局变量的首字母必须大写。必须用import引用定义全局变量的文件
用双引号""来定义字符串
支持指针,和C语言类似
str := new(string)
常量使用关键字 const 定义
type TypeAlias = Type 定义类型别名
普通函数声明:func 函数名(形式参数列表)(返回值列表)
支持对返回值进行命名,这样返回值就和参数一样拥有参数变量名和类型。直接return就能返回函数中同名的变量
函数也是一种类型,可以和其他类型一样保存在变量中,var f func()
func (s *Struct) Call(p interface{}) {} 代表使用结构体实现一个接口,表示这个是一个结构体的函数
函数体实现接口
函数的声明不能直接实现接口,需要将函数定义为类型后,使用类型实现结构体,当类型方法被调用时,还需要调用函数本体。
闭包,是指函数体和外部变量捕获的一种机制。Lambda匿名函数,会捕获环境中的参数捕获
可变参数:func myfunc(args ...int)
defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,类似finally 语句块,用于释放资源。defer 后的语句(f.Close())将会在函数返回前被调用,自动释放资源
当宕机发生时,程序会中断运行,并立即执行在该 goroutine(可以先理解成线程)中被延迟的函数(defer 机制),随后,程序崩溃并输出日志信息,日志信息包括 panic value 和函数调用的堆栈跟踪信息,panic value 通常是某种错误信息。
Recover 是一个Go语言的内建函数,可以让进入宕机流程中的 goroutine 恢复过来,recover 仅在延迟函数 defer 中有效,在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果,如果当前的 goroutine 陷入恐慌,调用 recover 可以捕获到 panic 的输入值,并且恢复正常的执行。
没有"类"的概念,也不支持"类"的继承等面向对象的概念
自带垃圾回收机制(GC)。GC 通过独立的进程执行,它会搜索不再使用的变量,并将其释放。需要注意的是,GC 在运行时会占用机器资源,runtime.GC() 函数,显式的执行 GC。
func SetFinalizer(x, f interface{})。
参数 x 必须是一个指向通过 new 申请的对象的指针,或者通过对复合字面值取址得到的指针。
参数 f 必须是一个函数,它接受单个可以直接用 x 类型值赋值的参数,也可以有任意个被忽略的返回值。
channel 是进程内的通信方式,channel 是类型相关的,定义一个 channel 时,也需要定义发送到 channel 的值的类型,注意,必须使用 make 创建 channel。发送:通道变量 <- 值,接收:data := <-通道变量或者非阻塞:data, ok := <-ch
goroutine 和 channel 是 Go 语言秉承的 CSP(Communicating Sequential Process)并发模式的重要实现基础。runtime.Gosched() 是让当前 goroutine 暂停的意思,退回执行队列
runtime.GOMAXPROCS(runtime.NumCPU()) 设置协程能使用的CPU数量
并发(concurrency):把任务在不同的时间点交给处理器进行处理。在同一时间点,任务并不会同时运行。并行(parallelism):把每一个任务分配给每一个处理器独立完成。在同一时间点,任务一定是同时运行。coroutine 始终顺序执行。goroutine 间使用 channel 通信,coroutine 使用 yield 和 resume 操作
代码工具
计算函数执行时间:start := time.Now() elapsed := time.Since(start)
单元测试文件,在命名文件时文件名必须以_test.go结尾
编写测试用例有以下几点需要注意:
测试用例文件不会参与正常源码的编译,不会被包含到可执行文件中;
测试用例的文件名必须以_test.go结尾;
需要使用 import 导入 testing 包;
测试函数的名称要以Test或Benchmark开头,后面可以跟任意字母组成的字符串,但第一个字母必须大写,例如 TestAbc(),一个测试用例文件中可以包含多个测试函数;
单元测试则以(t *testing.T)作为参数,性能测试以(t *testing.B)做为参数;
测试用例文件使用go test命令来执行,源码中不需要 main() 函数作为入口,所有以_test.go结尾的源码文件内以Test开头的函数都会自动执行。可以做压力测试和覆盖率测试