go从入门到进阶的笔记
做个流水账样式的笔记吧。在工作中用到go,但毕竟不是主力语言,有些地方可能用不到。
业务需要又必须有地方用到go,最近打算改造现有的c++服务,用go替换其中的业务部分。
最近看了徐波老师的go从入门到进阶。做了个流水笔记。
根据这些知识点写了一堆代码,比较丑陋,我就不贴了啊。
# 知识点大全
## 1 初始语言
新,简单,快,风格清晰,标准库强大
## 2 基本语法
变量的声明,赋值
匿名变量
数据类型:整型,浮点型,布尔型,字符串,
字符,
切片
类型转换
指针:类型指针,切片
1 声明指针
2 new()
变量生命周期:栈,堆
逃逸分析:自动决定变量分配方式,提高运行效率
1 分析逃逸 -gcflags "-m -l"
2 取址发生逃逸分析
3 原则
1 变量是否被取地址
2 变量是否发生了逃逸
字符串提供的操作
长度,取地址,连接
格式化
%v %+v %#v $T %% %b %o %d %x $X %U %f %p
常量const
枚举iota
类型别名和类型定义
type NewInt int
type IntAlias = int
非本地类型无法添加方法
## 3 容器:存储和组织数据的方式
数组:固定长度的连续内存区域
切片:动态分配大小的连续空间
1 数组或者切片产生
2 make
3 append copy 删除:
map
1 make
2 range
3 delete
4 清除,依赖垃圾回收
sync.Map
1 初始化
2 Store, Load, Delete
3 Range
container/list
1 初始化list.New()
2 PushBack PushFront
3 Next
## 4 流程控制
if
for
for range【array slice string map channel】
switch fallthrough
goto break continue
## 5 函数
函数一等公民: 值传递,匿名函数,闭包,满足接口
声明函数
1函数支持多值返回值
2支持直接返回变量
结构体在函数中是值传递
函数可以当做值
匿名函数
函数类型实现接口,函数赋值给接口
闭包:函数+引用环境
可变参数
...interface{}
延迟执行语句 defer
错误无处理 error
type error interface{Error() string}
panic 恐慌和recover
## 6 结构体
new 或 & 类型的指针
定义结构体
实例化结构体
1 var v1 T
2 new(T)
3 &T{}
初始化结构体的成员变量
1 初始多个值
2 初始化匿名对象
模拟构造函数
嵌入式模拟父级构造函数
方法
func (接收器类型) 方法名(参数列表)(返回参数){}
方法接收器
1 指针接收器
定义基本类型同名类型,添加方法
类型内嵌
1 可以直接访问内嵌的成员变量
2 字段名就是它的类型名
内嵌的组合
## 7 接口
声明接口,接口的命名规范
接口的实现条件:1 格式完全一样 2 方法都被实现
类型和接口的关系
使用接口抽象业务逻辑
接口嵌套
接口和类型间的转换:接口转类型,类型转接口
t := i.(T)
空接口类型 interface{}
1 值存储到空接口
2 空接口取值 i.(int)
空接口值比较
1 不同类比较结果不同,不能比较动态值
空类分支 (interface{}).(type)
## 8 包
GOPATH环境变量,提供项目的工作目录
多个GOPATH
创建包package
1 一个目录下的同级文件归属一个包
2 包名可以与目录不同
3 无main包不输出可执行文件
导出标识符:大写
导入包import
1 包别名 name xxx
2 匿名导入包 _ "xxx"
包的初始化 init
1 一个包一个
2 初始化顺序
工厂模式管理多个包的结构体
## 9 并发
创建协程go
使用匿名函数创建协程
runtime.GOMAXPROCS()设置核心数量
通道chan
make(chan XX)
通道发送数据:通道<-数据
通道接收数据:数据 :=<-通道
data,ok :=<-ch
for data :=range ch{}
单向通道 只发送:chan<-
单向通道 只接收:<-chan
带缓存的通道
通道的多路复用select
time.After 计时器
time.NewTicker 定点计时器
关闭通道 close
go run -race 检测竞争
同步之atomic
同步之互斥锁 sync.Mutex
sync.Mutex
sync.RWMutex
同步之等待组 sync.WaitGroup
## 10 反射
反射是指在程序运行期间对程序本身进行访问和修改的能力。
反射的类型对象 reflect.Type
reflect.TypeOf(a)
反射的类型Type,系统原生类型
反射的种类Kind,类型归属的种类
reflect.Elem获取指针指向的元素的类型
反射获取结果提的成员
Field(i)StructField
NumField()int
FieldByName(name)(StructField,bool)
FieldByIndex(index []int) StructField
FieldByNameFunc(match func(string)bool)(StructField,bool)
StructField
Name,PkgPath, Type, Tag, Index, Anonymous
StructTag
Get(key)string, Lookup(key)(string,bool)
反射的值对象reflect.Value
使用反射对象包装任意值 reflect.ValueOf(rawValue)
从反射值获取被包装的值
Interface()interface{}
Int(),Uint(),Float(),Bool(),Bytes(),String()
使用反射访问结构体的成员字段的值
Field(i)Value
NumberField()
FieldByName(name)Value
FieldByIndex(index []int)Value
FieldByNameFunc(match func(string)bool)Value
反射对象的空和有效性判断
isNil, isValid
使用反射值对象获取变量的值【先寻址,再修改】
Elem()类似*
Addr()类似&
CanAddr()bool
CanSet()bool
使用反射值对象修改相关的方法
SetInt,SetUint,SetFloat,SetBool,
SetBytes,SetString
通过类型创建类型的实例
1 reflect.New(typeOfA)
使用反射调用函数
funcValue.Call(xx)
## 11 编译与工具
go build
-v 包名
-p 并发编译
-a 强制重新构建
-race 开启竞态检测
go run
go install 编译并安装
go get
go test
文件 XX_test
方法 TestXX(t *testing.T)
test指定方法
go test -v -run TestA xxxx_test.go
终止测试 t.FailNow()
基准测试
Benchmark_Add(b *testing.B) b.N
go test -v -bench=. xxxx_test.go
自定义bench时间 -bench -benchtime=5s
测试内存 -bench=Alloc -benchmem xxx_test.go
控制计时器
b.ResetTimer() 重置
b.StopTimer() 停止
b.StartTimer() 开始
性能分析 go pprof
1 安装Graphviz 图形的工具包
2 runtime.pprof可以使用,但是不太方便
3 go get github.com/pkg/profile
4 go build
5 go tool pprof --pdf xxx xx.pprof > xx.pdf
## 12 避坑与技巧
### 合理地使用并发特性
1 了解goroutine的生命期再创建goroutine
创建,退出
2 避免在不必要的地方使用通道
1 通道为了保证goroutine并发访问,也需要做锁操作
3 反射:性能和灵活性的双刃剑
1 使用原生代码,避免反射
2 提前缓存反射对象对性能帮助较大
3 避免使用反射函数调用,实在需要时,提前缓冲函数参数列表,并尽量少使用返回值
4 nil只能被赋值给指针和接口
接口底层 type和data,都为nil是才是nil
发现返回nil时直接返回nil
基于哈希值的多键索引及查询
1 字符串转哈希值
2 查询键值
优雅的处理TCP粘包