Go语言必知的90个知识点
1. 函数可以返回函数类型
~~~
func test() func(int) {
return func(x int) {
println("x:", x)
}
}
~~~
2. defer定义延迟调用,无论函数是否出错都确保结束前被调用
3. ok-idiom(A跌目)模式:多返回值中用一个名为ok的布尔值来标记操作是否成功
4. 结构中的匿名字段,结构的实例可以直接调用匿名字段的方法和属性
5. 计算机中变量是一段或者多段用来存储数据的内存,类型决定变量内存的长度和存储格式,所以我们只能修改变量值不能修改类型
6. 内存分配发生在运行时,编译后的机器码不使用变量名而是直接使用内存地址访问目标数据,所以编码阶段采用易于阅读的变量名
7. 惯例建议以组的方式整理多行变量定义 var {x,y int } type{ xxx }
8. 简短声明一般用于函数多返回值,以及if for switch等语句中定义局部变量
9. 未使用的局部变量会编译出错,全局变量不报错
10. 命名建议字母或下划线开始,多字母数字和下划线组合,局部变量优先短名
11. 常量实在预处理阶段展开成指令数据,变量是在运行期分配存储内存.(所以常量无法寻址,没有地址)
12. byte是uint8的别名 rune是int32的别名 别名直接可以相互赋值不需要类型转换
13. 拥有相同的底层结构不代表就属于别名
14. new为指定类型分配零值内存返回指针;make是引用类型专用的创建函数(内存分配和属性初始化)
15. 未命名类型:数组、切片、字典、通道等类型与具体元素类型或长度等属性相关的类型,可以用type将其改变成命名类型
16. 对于未命名类型 struct tag不同也属于不同类型,字段顺序不同也属于不同类型。
17. 乘幂和绝对值运算在math包的Pow和Abs中
18. 自增自减只能作为独立语句
19. 指针是实体会分配内存空间,内存地址是内存中每个字节单元的唯一编号
20. 指针类型指向相同地址或nil则相等,但是不能做加减和类型转换
21. unsafe.Pointer将指针转换为uintptr进行加减运算,但可能造成非法访问
22. 指针不能用->,统一使用.
23. 复合类型初始化,必须包含类型标签;左花括号必须在类型尾部;多成员都好隔开;多行右侧必须是逗号或者花括号
24. switch 无需显式执行break,但是想顺序执行需要显式执行fallthrough
25. range迭代是复制数据
26. goto只能跳转到同级代码,不能跨级别
27. break用于switch for select,终止整个语句块执行
28. continue只用于for循环,终止后续逻辑立即进入下一轮循环
29. 函数无需前置声明;不支持命名嵌套定义;不支持同名重载;不支持默认参数;支持不定长参数;支持多返回值;支持命名返回值;支持匿名函数和闭包
30. 函数类型只支持nil判断,不支持其他比较操作
31. 从函数返回局部变量指针是安全的,编译器会通过逃逸分析来决定是否在堆上分配内存;所以参数尽量减少值拷贝
32. 函数建议命名规则:动词+名称;避免不必要的缩写(printError优于printErr);避免使用类型关键字;使用习惯用语(init表示初始化,is/has返回布尔值);用反义词命名行为相反的函数
33. 不管是指针、引用类型还是其天涯类型参数,都是值拷贝传递,区别在于拷贝的目标对象
34. 指针传递坏处在于延长该变量的声明周期,也可能导致他分配到堆上增加性能消耗
35. 函数参数在函数内部有效,作用域是整个函数内部
36. 变参 func test(a ...int){} test(a[:]...)
37. 命名返回值的问题: 新定义的同名局部变量会引起同名遮蔽:xx is shadowed during return ;此时实名return即可
38. 闭包 匿名函数能够使用上下文的环境中的数据(最终数据)
39. 延迟调用defer 常用于资源释放 解除锁定 错误处理等 先入后出。 延迟调用开销很大,性能要求高压力大的算法尽量避免使用
40. error是接口类型
41. panic会引发函数中断执行defer ,在defer中使用recover捕获panic提交的错误对象(recover只能在defer中执行才有效)
42. 多个panic仅最后一个被捕获
43. runtime/debug.PrintStrack()可以打印完整的堆栈信息
44. 不可恢复性、导致系统无法正常工作的错误才会使用panic (文件系统没权限操作、服务端口被占用、数据库未启动等)
45. 字符串是不可变字节(byte)序列,可用len获取长度,不可用cap; ` 支持跨行;允许字节数组访问,单不允许字节数组取地址
46. 用切片指向数组时,底层还是指向该字符串
47. range遍历可以打印出汉字,len遍历出的汉字是乱码
48. append可以向[]byte追加 =》var bs []byte bs=append(bs,"abc"...)
49. 字符串加法运算每次都会重新分配内存,构建大字符串性能极差;方法1:strings.Join 方法2:bytes.Buffer 小字符串拼接使用fmt.Sprintf text/template等
50. utf8.RuneCountInString(s)代替len获取带汉字的字符串长度
51. 长度是数组的类型组成部分,元素类型相同长度不同的数组不是同一类型
52. 多维数组,只第一维支持... => [...][10]
53. 如果元素支持== !=操作,则数组也支持
54. 数组是值类型
55. 切片:不是动态数组或数组指针;内部通过指针引用底层数组,设定相关属性将数据读写操作限定在指定区域内。可以理解为数组指针的包装
56. 切片本身是只读对象,工作机制类似数组指针的包装 右半开区间 数组必须addressable
~~~
type slice struct{
array unsafe.Pointer
len int
cap int
}
~~~
57. 切片引用数组时,切片指针会指向数组地址;访问越界会报错;append会追加数组,当长度大于cap时会重新分配地址,则切片和数组就相互独立了
58. 切片 var a[]int 为nil,仅代表他为初始化,但依旧分配内存;且a[:]依旧是nil
59. 如果切片长时间占用大数组的少量数据,建议切片单独分配地址,以让大数组尽早释放
60. 可将字符串直接复制到[]byte => b:=make([]byte,3) n:=copy(b,"abcdefhg")=>n=3,b=[97 98 99]
61. 字典的key必须支持== != 如数字、字符串、指针、数组、结构、接口
62. if v,ok:=m["d"];ok{存在} 使用ok-idiom模式判断key是否存在
63. delete(m,"d"),删除不存在的key不报错
64. map使用range迭代每次顺序不定
65. map被设计成 no addressable,所有没法修改value的成员(如果value是个结构或者数组等) ;改进方法1:先获取完整value,修改后再赋值回去;方法2:value采用指针类型。因为value是指针,所有可以通过指针修改指针指向的数据。
66. map并发操作,某任务针对map写操作,其他任务对该map的读写删除都会导致进程崩溃;可用sync.RWMutex实现同步(不要使用defer)
67. map对象本身就是指针包装,传参不需要取地址
68. map创建时和slice一样要预选分配足够地址,减少扩张时不必要的内存分配和重新哈希操作=>make(map[int]int,1000)
69. 对于海量小对象,应该直接用字典存储键值数据拷贝而不是指针,这样减少扫描对象的数量缩短垃圾回收时间。
70. 字典不会收缩内存,适当替换新对象是有必要的
71. 结构推荐命名初始化,以防扩充结构时报错
匿名结构:
~~~
u:=struct{
name string
}{
name:"xxx",
}
~~~
72. 只有所有成员都支持==操作时,结构才支持相等操作
73. 匿名字典隐式的以类型名为字段名称,使用时可以直接饮用匿名字段的成员,但是初始化时必须当做独立字段。(但是隐式字段是外部类型的话,隐式名称不包含包名)
74. 除接口指针 多级指针外的任何命名类型都可作为匿名类型
75. 字段标签是对字段描述的元数据,是类型的组成部分;运行期间可用反射获取标签信息,通常作为格式校验和数据库关系映射等
~~~
p1:=p{
name:"xxx",
sex:1,
}
v:=reflect.ValueOf(p1)
t:=v.Type()
for i,n:=0,t.NumField();i<n;i++{
fmt.Printf("%s:%v\n",t.Field(i).Tag,v.Field(i))
}
~~~
76. reflect.StructTag提供了更完善的功能
77. 前置实例接收参数-receiver
78. receiver是基础类型则会被复制,指针类型则必须能获取实例地址
79. receiver类型选择:不修改的小对象或固定值用T;引用类型、字符串、函数等指针包装对象用T;修改实例状态用*T;包含Mutex等同步字段用*T,大对象或不确定情况用*T;
80. 匿名类型的方法也存在同名遮蔽的特性。(可实现类似覆盖操作)
81. T的方法集是 receiver T;*T的方法集是receiver T+*T
82. 匿名嵌入S,T包含 receiver S;匿名嵌入*S,T包含 receiver S+*S; 匿名嵌入S或*S,*T都包含 receiver S+*S;
83. 方法集仅影响接口实现和方法表达式转换。匿名字段就是为方法集准备的
84. Chan:
一次性事件使用chan的close效率更高
向close的chan发数据panic
从已关闭的chan接收数据返回已缓存数据或零值
无论收发,nil通道都会阻塞
85. Chan和锁的选择:
同步问题应该用锁或原子变量来操作
对性能要求较高时,赢避免使用defer unlock
读写并发时,用RWMutex性能更好
对单个数据的读写保护建议使用读写锁
严格测试,尽可能打开数据竞争检查
通道倾向于解决逻辑层次的并发处理架构
锁用来保护局部范围内的数据安全
86. FieldByName不支持多级名称,如有同名遮蔽需要匿名字段二级获取
87. 可用发射提取struct tag还能自动分解,常用于ORM映射或数据格式验证
88. 反射可通过Interface方法进行类型推断和转换
89. 对性能要求较高的地方需要谨慎使用反射
90. Go语言1.5版本实现的自举
- 序言
- 目录
- 环境搭建
- Linux搭建golang环境
- Windows搭建golang环境
- Mac搭建golang环境
- Go 环境变量
- 编辑器
- vs code
- Mac 安装vs code
- Windows 安装vs code
- vim编辑器
- 介绍
- 1.Go语言的主要特征
- 2.golang内置类型和函数
- 3.init函数和main函数
- 4.包
- 1.工作空间
- 2.源文件
- 3.包结构
- 4.文档
- 5.编写 Hello World
- 6.Go语言 “ _ ”(下划线)
- 7.运算符
- 8.命令
- 类型
- 1.变量
- 2.常量
- 3.基本类型
- 1.基本类型介绍
- 2.字符串String
- 3.数组Array
- 4.类型转换
- 4.引用类型
- 1.引用类型介绍
- 2.切片Slice
- 3.容器Map
- 4.管道Channel
- 5.指针
- 6.自定义类型Struct
- 流程控制
- 1.条件语句(if)
- 2.条件语句 (switch)
- 3.条件语句 (select)
- 4.循环语句 (for)
- 5.循环语句 (range)
- 6.循环控制Goto、Break、Continue
- 函数
- 1.函数定义
- 2.参数
- 3.返回值
- 4.匿名函数
- 5.闭包、递归
- 6.延迟调用 (defer)
- 7.异常处理
- 8.单元测试
- 压力测试
- 方法
- 1.方法定义
- 2.匿名字段
- 3.方法集
- 4.表达式
- 5.自定义error
- 接口
- 1.接口定义
- 2.执行机制
- 3.接口转换
- 4.接口技巧
- 面向对象特性
- 并发
- 1.并发介绍
- 2.Goroutine
- 3.Chan
- 4.WaitGroup
- 5.Context
- 应用
- 反射reflection
- 1.获取基本类型
- 2.获取结构体
- 3.Elem反射操作基本类型
- 4.反射调用结构体方法
- 5.Elem反射操作结构体
- 6.Elem反射获取tag
- 7.应用
- json协议
- 1.结构体转json
- 2.map转json
- 3.int转json
- 4.slice转json
- 5.json反序列化为结构体
- 6.json反序列化为map
- 终端读取
- 1.键盘(控制台)输入fmt
- 2.命令行参数os.Args
- 3.命令行参数flag
- 文件操作
- 1.文件创建
- 2.文件写入
- 3.文件读取
- 4.文件删除
- 5.压缩文件读写
- 6.判断文件或文件夹是否存在
- 7.从一个文件拷贝到另一个文件
- 8.写入内容到Excel
- 9.日志(log)文件
- server服务
- 1.服务端
- 2.客户端
- 3.tcp获取网页数据
- 4.http初识-浏览器访问服务器
- 5.客户端访问服务器
- 6.访问延迟处理
- 7.form表单提交
- web模板
- 1.渲染终端
- 2.渲染浏览器
- 3.渲染存储文件
- 4.自定义io.Writer渲染
- 5.模板语法
- 时间处理
- 1.格式化
- 2.运行时间
- 3.定时器
- 锁机制
- 互斥锁
- 读写锁
- 性能比较
- sync.Map
- 原子操作
- 1.原子增(减)值
- 2.比较并交换
- 3.导入、导出、交换
- 加密解密
- 1.md5
- 2.base64
- 3.sha
- 4.hmac
- 常用算法
- 1.冒泡排序
- 2.选择排序
- 3.快速排序
- 4.插入排序
- 5.睡眠排序
- 限流器
- 日志包
- 日志框架logrus
- 随机数验证码
- 生成指定位数的随机数
- 生成图形验证码
- 编码格式转换
- UTF-8与GBK
- 解决中文乱码
- 设计模式
- 创建型模式
- 单例模式
- singleton.go
- singleton_test.go
- 抽象工厂模式
- abstractfactory.go
- abstractfactory_test.go
- 工厂方法模式
- factorymethod.go
- factorymethod_test.go
- 原型模式
- prototype.go
- prototype_test.go
- 生成器模式
- builder.go
- builder_test.go
- 结构型模式
- 适配器模式
- adapter.go
- adapter_test.go
- 桥接模式
- bridge.go
- bridge_test.go
- 合成/组合模式
- composite.go
- composite_test.go
- 装饰模式
- decoretor.go
- decorator_test.go
- 外观模式
- facade.go
- facade_test.go
- 享元模式
- flyweight.go
- flyweight_test.go
- 代理模式
- proxy.go
- proxy_test.go
- 行为型模式
- 职责链模式
- chainofresponsibility.go
- chainofresponsibility_test.go
- 命令模式
- command.go
- command_test.go
- 解释器模式
- interpreter.go
- interperter_test.go
- 迭代器模式
- iterator.go
- iterator_test.go
- 中介者模式
- mediator.go
- mediator_test.go
- 备忘录模式
- memento.go
- memento_test.go
- 观察者模式
- observer.go
- observer_test.go
- 状态模式
- state.go
- state_test.go
- 策略模式
- strategy.go
- strategy_test.go
- 模板模式
- templatemethod.go
- templatemethod_test.go
- 访问者模式
- visitor.go
- visitor_test.go
- 数据库操作
- golang操作MySQL
- 1.mysql使用
- 2.insert操作
- 3.select 操作
- 4.update 操作
- 5.delete 操作
- 6.MySQL事务
- golang操作Redis
- 1.redis介绍
- 2.golang链接redis
- 3.String类型 Set、Get操作
- 4.String 批量操作
- 5.设置过期时间
- 6.list队列操作
- 7.Hash表
- 8.Redis连接池
- 其它Redis包
- go-redis/redis包
- 安装介绍
- String 操作
- List操作
- Set操作
- Hash操作
- golang操作ETCD
- 1.etcd介绍
- 2.链接etcd
- 3.etcd存取
- 4.etcd监听Watch
- golang操作kafka
- 1.kafka介绍
- 2.写入kafka
- 3.kafka消费
- golang操作ElasticSearch
- 1.ElasticSearch介绍
- 2.kibana介绍
- 3.写入ElasticSearch
- NSQ
- 安装
- 生产者
- 消费者
- zookeeper
- 基本操作测试
- 简单的分布式server
- Zookeeper命令行使用
- GORM
- gorm介绍
- gorm查询
- gorm更新
- gorm删除
- gorm错误处理
- gorm事务
- sql构建
- gorm 用法介绍
- Go操作memcached
- beego框架
- 1.beego框架环境搭建
- 2.参数配置
- 1.默认参数
- 2.自定义配置
- 3.config包使用
- 3.路由设置
- 1.自动匹配
- 2.固定路由
- 3.正则路由
- 4.注解路由
- 5.namespace
- 4.多种数据格式输出
- 1.直接输出字符串
- 2.模板数据输出
- 3.json格式数据输出
- 4.xml格式数据输出
- 5.jsonp调用
- 5.模板处理
- 1.模板语法
- 2.基本函数
- 3.模板函数
- 6.请求处理
- 1.GET请求
- 2.POST请求
- 3.文件上传
- 7.表单验证
- 1.表单验证
- 2.定制错误信息
- 3.struct tag 验证
- 4.XSRF过滤
- 8.静态文件处理
- 1.layout设计
- 9.日志处理
- 1.日志处理
- 2.logs 模块
- 10.会话控制
- 1.会话控制
- 2.session 包使用
- 11.ORM 使用
- 1.链接数据库
- 2. CRUD 操作
- 3.原生 SQL 操作
- 4.构造查询
- 5.事务处理
- 6.自动建表
- 12.beego 验证码
- 1.验证码插件
- 2.验证码使用
- beego admin
- 1.admin安装
- 2.admin开发
- beego 热升级
- beego实现https
- gin框架
- 安装使用
- 路由设置
- 模板处理
- 文件上传
- gin框架中文文档
- gin错误总结
- 项目
- 秒杀项目
- 日志收集
- 面试题
- 面试题一
- 面试题二
- 错题集
- Go语言陷阱和常见错误
- 常见语法错误
- 初级
- 中级
- 高级
- Go高级应用
- goim
- goim 启动流程
- goim 工作流程
- goim 结构体
- gopush
- gopush工作流程
- gopush启动流程
- gopush业务流程
- gopush应用
- gopush新添功能
- gopush压力测试
- 压测注意事项
- rpc
- HTTP RPC
- TCP RPC
- JSON RPC
- 常见RPC开源框架
- pprof
- pprof介绍
- pprof应用
- 使用pprof及Go 程序的性能优化
- 封装 websocket
- cgo
- Golang GC
- 查看程序运行过程中的GC信息
- 定位gc问题所在
- Go语言 demo
- 用Go语言计算一个人的年龄,生肖,星座
- 超简易Go语言实现的留言板代码
- 信号处理模块,可用于在线加载配置,配置动态加载的信号为SIGHUP
- 阳历和阴历相互转化的工具类 golang版本
- 错误总结
- 网络编程
- 网络编程http
- 网络编程tcp
- Http请求
- Go语言必知的90个知识点
- 第三方库应用
- cli应用
- Cobra
- 图表库
- go-echarts
- 开源IM
- im_service
- 机器学习库
- Tensorflow
- 生成二维码
- skip2/go-qrcode生成二维码
- boombuler/barcode生成二维码
- tuotoo/qrcode识别二维码
- 日志库
- 定时任务
- robfig/cron
- jasonlvhit/gocron
- 拼多多开放平台 SDK
- Go编译
- 跨平台交叉编译
- 一问一答
- 一问一答(一)
- 为什么 Go 标准库中有些函数只有签名,没有函数体?
- Go开发的应用
- etcd
- k8s
- Caddy
- nsq
- Docker
- web框架