Go学习笔记

安装

  • 访问这里 ,下载安装包进行安装即可。或者访问这里下载也可。

  • 配置go mod proxy,参考https://goproxy.cn即可。

  • 安装VSCode+Go插件或者Goland等开发工具都可以。


最近得在Linux上编译个服务端程序,所以把配置方法记录一下。

源用的是USTC的。看了他们官网发现东西还真不少比隔壁tuna多多了而且域名还短(确信)。golang直接下载太慢所以走镜像站。链接在这,时效性应该不用太担心。

https://mirrors.ustc.edu.cn/golang/go1.20.1.linux-amd64.tar.gz

步骤很简单,就是wget然后tar解压到指定位置最后把目录加到系统环境变量里边:

1
2
3
4
5
6
7
8
VER="1.20.1"
SH="bash"
# 下载解压 & 移除旧版本
wget https://mirrors.ustc.edu.cn/golang/go"$VER".linux-amd64.tar.gz \
&& rm -rf /usr/local/go \
&& tar -C /usr/local -zxf go$GO_STR.linux-amd64.tar.gz
# 如果是第一次安装且使用bash
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/."$SH"rc

注意:执行上面的脚本之前请先自行验证安全性。以及,上面的脚本得用root权限执行。

然后就是设置代理。我用http://goproxy.cn比较多。配置也很简单:

1
2
export GO111MODULE=on
export GOPROXY=https://goproxy.cn

资料

常见问题

  • Go test报错

报错内容:call has possible formatting directive %v

原因:go test 中不能使用 fmt.Println("%v", v)

方案

使用 fmt.Printf("%+v", v)

工具链

现代语言最大的优势就是工具链。

1
go tool dist list

依赖:

1
ldd [bin-name]

静态编译:

1
2
3
CGO_ENABLED=0 go build xxx
# or this
go build xxx -ldflags '-linkmode "external" -extldflags "-static"'

如果glibc版本不对的话,直接使用指定LD_LIBRARY_PATH=.的方法是无效的。

ref:Glibc is hard-coded in the program

造轮子

采用组合的方式将常用的范式写成函数,同时不失灵活性和潜力。

Gin

对于Gin的复用主要是添加路由的方式进行抽象和标准化,同时编写一些较为通用的API Handlers:

1
2
3
4
5
6
7
8
9
func APIBuilder(router gin.IRouter, handlers ...func(*gin.RouterGroup) *gin.RouterGroup) func(gin.IRouter, string) *gin.RouterGroup {
return func(router gin.IRouter, path string) *gin.RouterGroup {
group := router.Group(path)
for _, handler := range handlers {
group = handler(group)
}
return group
}
}

上面的函数实现了为一个gin.RouterGroup自动添加参数传入的handler列表。这样的构造器构造出的函数能用于给一个接口添加几个固定的Handler。在复用层面实现了快速的为一个结构体添加CRUD的能力,同时允许你编写自己的handler代码,以及自己的构造器。

1
2
3
4
5
6
7
8
9
10
func AddCRUD[T any](router gin.IRouter, path string, db *gorm.DB) *gin.RouterGroup {
return APIBuilder(router, func(group *gin.RouterGroup) *gin.RouterGroup {
group.GET("", getAll[T](db))
group.GET("/:id", get[T](db))
group.POST("", create[T](db))
group.PUT("/:id", update[T](db))
group.DELETE("/:id", delete[T](db))
return group
})(router, path)
}

上面展示的就是构造器的一个用法,这个构造器构造的函数能用来快速给一个结构体添加CRUD接口。

其中的Handler可以自己实现,并把自己的Handler通过上面的APIBuilder打包成一个可以快速调用的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 简单的Handler示范
func create[T any](db *gorm.DB) func(c *gin.Context) {
return func(c *gin.Context) {
var d T
if err := c.ShouldBindJSON(&d); err != nil {
c.AbortWithStatus(404)
log.Println("[gorm]parse creation data failed: ", err)
} else {
if err := db.Create(&d).Error; err != nil {
c.AbortWithStatus(404)
log.Println("[gorm]create data failed: ", err)
} else {
c.JSON(200, d)
}
}
}
}
// 简单的调用示范
type Hello struct {
Hello string
World string
}
r := gin.Default
db, _ := gorm.Open(sqlite.Open("test"), &gorm.Config{})
AddCRUD[Hello](r, "/hello", db)

上面几行代码就添加了四个对于Hello的CRUD API。

而且你应该注意到了,上面crud的实现我传入了gorm.DB来完成实际的crud动作。主要是因为数据库查询的动作我不知道应该怎么传入,而且又不想自己搓个大而全的框架出来——简洁的函数更合我的胃口。

下一步就是尝试抽象以前自己编写的后端,试着用简洁又不失灵活度的方法创建一个渐进式辅助函数包。

最近发现了go-zero这个脚手架,主打面向k8s整微服务开发。框架做的还行,甚至基于go语法搓了个DSL出来。里边包含的单体微服务的框架对我有比较大的启发作用,我打算把它变成一个更FP的工具包拿来用。
以及Goland好像看着确实不错。

作者

xeonds

发布于

2022-05-06

更新于

2024-05-13

许可协议

评论