Go 语言进阶-工程进阶 | 青训营笔记

144 阅读4分钟

Go 语言进阶 - 工程进阶 | 青训营笔记

这是我参与「第五届青训营 」笔记创作活动的第2天,今天主要对Go语言的进阶内容进行学习。

一、本堂课重点内容:

本次课程讲了以下几个方面:

  1. 并发编程

  2. 依赖管理

  3. 单元测试

  4. 项目实战

二、详细知识点介绍:

1.并发编程

并发编程在当前软件领域是一个非常重要的概念,随着CPU等硬件的发展,我们无一例外的想让我们的程序运行的快一点、再快一点。

(1)并发vs并行

   并发:同一时间段内执行多个任务(可以理解成你在用微信和两个女朋友聊天)。

   并行:同一时刻执行多个任务(可以理解成你和你朋友都在用微信和女朋友聊天)。

(2)Goroutine

Goroutine 是 Go 语言支持并发的核心,Go语言中使用 goroutine 非常简单,只需要在函数或方法调用前加上go关键字就可以创建一个 goroutine ,从而让该函数或方法在新创建的 goroutine 中执行。

go f1()  // 创建一个新的 goroutine 运行函数f1

(3)Channel

Go语言提倡通过通信共享内存而不是通过共享内存而实现通信。Go 语言中的通道(channel)是一种特殊的类型。通道像一个传送带或者队列,保证收发数据的顺序。

channel是 Go 语言中一种特有的类型。声明通道类型变量的格式如下:

```go
var 变量名称 chan 元素类型
```

(4)并发安全和锁

有时候我们的代码中可能会存在多个 goroutine 同时操作一个资源(临界区)的情况,这种情况下就会发生竞态问题(数据竞态)。在Go语言中我们可以使用sync包下的WaitGroup和Mutex 来应对并发安全和锁问题

2.依赖管理

Go语言的依赖管理经历了 GOPATH -> Go Vendor -> Go Module,由于GOPATH存在无法实现package的多版本控制的问题,引入了Go Vendor,随之而来就是Go Vendor存在无法控制依赖的版本和更新项目又可能出现依赖冲突,导致编译出错等问题,最终Go Module出现了,Go Module通过go.mod文件管理依赖包版本,通过go get/go mod指令工具管理依赖包,终极目标是定义版本规则和管理项目依赖关系。

常用的go getgo mod命令:

go get example.org/pkg +
					   @update	默认
					   @none 	删除依赖
					   @v1.1.2	tag版本,语义版本
					   @23dfdd5	特定的commit
					   @master	分支的最新commit
go mod + 
		init 		初始化,创建go.mod文件
		download	下载模块到本地缓存
		tidy 		增加需要的依赖,删除不需要的依赖

3.单元测试

​ 测试是避免事故的最后一道屏障,测试可以分为回归测试集成测试单元测试,从上到下,覆盖率逐层变大,成本却逐层降低。Go语言中的测试依赖go test命令,go test命令是一个按照一定约定和组织的测试代码的驱动程序。在包目录内,所有以_test.go为后缀名的源代码文件都是go test测试的一部分,不会被go build编译到最终的可执行文件中。

4.项目实战

(1)需求描述:

​ 实现青训营话题页

​ 1.实现一个展示话题(标题,文字描述)和回帖列表的后端http接口;

​ 2.本地文件存储数据

三、实践练习例子:

在这个部分主要记录一下青训营话题页案例的实现思路和关键代码。

使用到的组件及技术点有:

(1)web框架:Gin 是一个用 Go 编写的 HTTP Web 框架,具有快速支持中间件路由组等特性。

(2)分层结构设计

(3)文件操作

(4)数据查询

入口文件server.go代码如下:

package main

//引用第三方模块
import (
	"github.com/Moonlight-Zhao/go-project-example/handler"
	"github.com/Moonlight-Zhao/go-project-example/repository"
	"github.com/Moonlight-Zhao/go-project-example/util"
	"gopkg.in/gin-gonic/gin.v1"
	"os"
)
//主函数
func main() {
  	//调用Init函数进行初始化
	if err := Init(); err != nil {
		os.Exit(-1)
	}
  	
  	//调用gin包的Default函数,生成r引擎
	r := gin.Default()
  	
  	//使用Logger中间键
	r.Use(gin.Logger())

  	//GET请求的测试接口,路径为/ping,响应状态码为200,内容为{"message":"pong"}
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
  
	//GET请求的获取文章内容接口,路径为/community/page/get/:id,id为文章id
	r.GET("/community/page/get/:id", func(c *gin.Context) {
		topicId := c.Param("id")
		data := handler.QueryPageInfo(topicId)
		c.JSON(200, data)
	})
  
  	//POST请求的提交文章内容接口,路径为/community/post/do
	r.POST("/community/post/do", func(c *gin.Context) {
		uid, _ := c.GetPostForm("uid")
		topicId, _ := c.GetPostForm("topic_id")
		content, _ := c.GetPostForm("content")
		data := handler.PublishPost(uid, topicId, content)
		c.JSON(200, data)
	})
        //使用Run方法启动后台服务器,默认端口为8080
	err := r.Run()
	if err != nil {
		return
	}
}
//Init函数
func Init() error {
  	//初始化存储仓库
	if err := repository.Init(); err != nil {
		return err
	}
  	//初始化日志
	if err := util.InitLogger(); err != nil {
		return err
	}
	return nil
}

四、课后个人总结:

​ 通过学习Go 语言进阶 - 工程进阶,学习到了Go语言的并发编程,还学到了Go语言的Go Module模块化管理、测试,最后通过一个青训营话题页案例,了解到Gin框架,以及使用Gin框架进行服务端开发。

五、引用参考:

​ 博客:www.liwenzhou.com/posts/Go/go…