Go上手笔记(一)(Java选手角度) | 青训营笔记

176 阅读8分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记。

包含前两天的课程笔记,如有错误还请指正。【有船启航】

Day01

第一天的内容比较零散,所以以点来记,而不使用课程大纲。

一、基础知识点

  1. 变量和常量名首字母大写时为可被包外调用的,类似java的public关键字

  2. switch-case用法更多变,可以在switch后省略,case后写条件

  3. make()造切片。但append()必须返还给原切片,切片的构成为长度、容量、底层数组指针,所以切片应该是值传递。copy()用来从两个切片中传递拷贝

  4. 容量不够会发生扩容,扩容与底层数组的长度有关

  5. 类似Python的切片操作:语法:slice[i:j] 第一个参数为开始索引,第二个为结束索引,左闭右开区间。注意,两个参数都可以省略,当省略开始索引时,默认值为0,省略结束索引时默认值为切片长度

  6. 可以通过make()函数造map,map还是类似java的,同为键值对。语法:map[key type]value type

  7. map的读取也和java中类似。

  • 注:
  • ①可以通过返回值ok(bool类型)判断某key在map中是否存在,存在为true,否则为false;
  • ②Go中一个函数的返回值类型可以有多个,具体就如同上述ok
  1. map的读取也和java中类似,注意:①可以通过返回值ok(bool类型)判断某key在map中是否存在,存在为true,否则为false;②Go中一个函数的返回值类型可以有多个,具体就如同上述ok

  2. 可以通过delete()函数删除键值对

  3. range对于array的两个参数分别返还为索引和当前值,对于map则为键和值

  4. 解决值传递时,Go可以通过指针,即在写函数时在形参类型和变量前添加*,在调用函数时,传入实参时前面添加&

  5. 结构体同样可以使用指针

  6. 结构体方法类似于java中的类方法,需要在方法名前添加接收类型,并用括号包围,调用时就可以使用接收类型的变量调用了。同样可以使用指针。

  7. 错误处理:写函数时,返回值类型中添加error,在可能出错函数返回中new一个;调用函数时,可以用error类型接收,并进行判断和处理。

  8. 字符串操作和字符串格式化,建议直接查文档中的strings包和fmt包,Go里面的字符串可能类似java中的StringBufferStringBuilder(还不确定!我还得看看文档。英文过关的可以用zeal软件,下载离线文档)

  9. json处理,公开字段(首字母大写)可以使用json包的MarshalIndent()函数进行序列化,返回byte数组,再通过jsonUnmarshal()函数反序列化

  10. json的风格可以在结构体字段后修改

  11. time包的时间格式是固定时间:"2006-01-02 15:04:05",而非"yyyy-MM-dd hh:mm:ss"

  12. 字符转换,通过strconv包下的函数

二、实战

随机数问题:

v1,需要随机数种子,不然每次都是一样的数(可以利用时间戳初始化随机数种子)

v2,用户输入的读取,取只读的流,读取流中的字符,将字符串中的换行符去除,将字符串转换为数字

v3,判断逻辑

v4,实现循环,直至猜对时break

命令行词典:

(发送Http请求,解析json)

代码生成的网址:curlconverter.com/#go

解析响应体网址:oktools.net/json2go

  • 要复制curl(bash)
  • 返回的响应同样是流,要先检测确认是否出错,为了避免资源浪费,需要手动关闭(珍惜资源同java里的操作)
  • 然后构造结构体,与json的字段一一对应

代理问题:

Day02

第二天的内容涉及到项目结构,老老实实按老师的大纲来了。(绝不是因为老师语速快)(引用了课件,若不允许,联系删改)

1.语言进阶

1.1并行并发

并发:一个CPU上 ,应用程序可能不会在同一时间完成多个任务,但在应用程序内部一次完成多个任务。要同时在多个任务上取得进展,CPU会在执行期间在不同的任务之间切换。

并行:多个 CPU 或 CPU 内核,并同时在多个任务上取得进展。但是,并行执行并不是指与并行性相同的现象 。

image.png

Go提高了并发调度模型,发挥多核计算机的优势。

协程:用户态,轻量级线程,栈KB级别。(PPT有误)

线程:内核态,线程跑多个协程,栈MB级别。

  • 注:主协程如果执行完毕了,那么子协程会终止,需让主协程等待或接收子协程的执行运作。

1.2通道(类似传输队列,保证收发数据的顺序)

image.png

Go除去通过通信共享内存,也保留通过共享内存实现通信。但通过共享内存实现通信需要互斥量的加速,也就是需要获取临界区的权限,但会发生数据竞态,影响性能。注:最好通过Lock加锁,保证对于统一数据的操作安全(并发安全)。

语法:make(chan 元素类型,缓冲大小)

  • 无缓冲通道 如make(chan int):同步通道,会导致发收的gorountine同步化,
  • 有缓冲通道 如make(chan int,2):类似于队列、生产消费模型,解决生产消费的效率不均问题

2.管理包

2.1.1 GOPATH

直接依赖src下的代码,通过go get下载最新版本的包道src目录下

缺点:无法实现package的多版本控制

2.1.2 Go Vendor

依赖优先从vendor文件获取,找不到再回GOPATH找。解决多个项目需要同一个package的冲突问题。

缺点:当两个轮子依赖了另一个轮子A的不同版本,则会产生冲突。即无法控制依赖的版本;更新项目又可能出现依赖冲突,导致编译出错。原因是依赖项目源码,并不能清晰的解决依赖的版本。

2.1.3 Go Module

通过go.mod文件管理依赖包版本 通过go get/go mod指令工具管理依赖包

2.2 依赖管理三要素

  1. 配置文件,描述依赖 go.mod indirect 直接依赖 incompatiable 不兼容

  2. 中心仓库管理依赖库 Proxy 依赖分发 变量GOPROXY->go mod direct 若镜像网站没有依赖,就回官网

  3. 本地工具 go get/mod

3.测试

3.1 回归测试 v 集成测试 v 单元测试

从左到右,覆盖率逐层变大,成本逐层降低

回归测试:质量保证员通过终端测试主流;基于自动化的回归测试,集中功能维度;面对测试开发阶段,对单独函数模块进行测试。

3.2 规范

所有测试文件以_test.go结尾 func TestXxx(*testing.T) 初始化逻辑放到TestMain中,入参为m testing.M(可*指针),然后用m.Run(),执行该package下的所有单元测试 运行:go test [flags] [packages]

3.3 代码覆盖率

通过 go test *_test.go *.go --cover 执行单测并计算代码覆盖率

  • 注:

  • ①一般覆盖率:50%~60%,较高覆盖率80%+。

  • ②测试分支相互独立、全面覆盖。

  • ③测试单元粒度足够小 -> 函数需要小,函数单一职责。

3.4 依赖

单元测试的目标:稳定性、幂等性

单元测试不稳定 -> Mock机制(开源mock包:monkey : github.com/bouk/monkey

快速Mock函数: 原理:一个(打桩)函数替代另一个(原)函数

  • 注:记得将打桩函数卸载,可通过defer关键字

3.5 基准测试(压力测试,性能分析)

  1. 规范:func BenchmarkXxx(b *testing.B)

  2. 细节刨除非测试代码的损耗:通过计时器重置

4 项目实战(实现一个Web服务)

4.1 需求设计

4.1.1社区话题页面——掘金回帖

  1. 话题展示和回帖列表
  2. 实现一个web服务,不实现前端
  3. 话题和回帖数据用文件存储

4.1.2 用例分析

image.png

4.1.3 分层结构(此处就不多说了,java的同学应该很熟悉SpringMVC的流程)

4.2 代码开发

DAO层:

  1. 设计Topic和Post两个实体的属性image.png
  2. 初始化数据索引 sync.Once:是 Go 中使方法只执行一次的对象实现,适用于高并发场景下的只执行一次的情况
  3. 提供查询函数

Service层:业务逻辑

业务逻辑:参数校验-->准备数据-->组装实体

image.png

  • 注:
  • ①准备数据:案例的数据都依赖于Id,两个流程没有前后顺序,可以使用并行执行,提高效率
  • ②使用子协程,要确保主协程在子协程执行完后结束
  • ③注意err,包括控制流程的退出,使得页面信息正常返回

Controller层:流程控制

  1. 构建View对象,通过code、msg打包业务状态信息,用data承载业务实体信息
  2. 处理业务错误码

通过gin搭建web框架:实现接口

  1. 初始化数据索引,遍历数据文件,生成索引map
  2. 初始化引擎配置,将path映射到具体controller,通过 path变量 传递 话题Id
  3. 构建路由
  4. 启动服务

4.3 测试运行