本期的次要内容将手把手教会大家,编写probuf的go插件,以我本人编写的一个生成构造体的插件为例子。我的项目位于 https://github.com/hisheng/pr…
一、自定义ProtoBuf插件介绍
咱们罕用的go反对protobuf插件有
插件名称 | 介绍 |
---|---|
protoc-gen-go | 通过.proto文件生成.pb.go文件 |
protoc-gen-doc | 通过.proto文件生成文档 |
protoc-gen-go-errors | 通过.proto文件生成error |
protoc-gen-go-errors | 通过.proto文件生成error |
protoc-gen-go-grpc | 通过.proto文件生成grpc |
protoc-gen-go-http | 通过.proto文件生成http |
protoc-gen-openapi | 通过.proto文件生成openapi |
protoc-gen-validate | 通过.proto文件生成validate验证 |
protoc-gen-go-enum | 通过.proto文件生成go自定义枚举 |
基本上该有的插件,都曾经有写过了,所以咱们能够查看他人的源码,来察看怎么来写一个插件。
二、手把手写自定义插件(以protoc-gen-go-struct为例)
2.1 新建protoc-gen-go-struct文件夹,并且进入到这个文件夹里。
mkdir protoc-gen-go-struct && cd protoc-gen-go-struct
2.2 新建go module我的项目
咱们执行 go mod init modName 命名来生成我的项目如下:
go mod init github/hisheng/protoc-gen-go-struct
此时咱们查看文件夹发现生产了一个 go.mod文件,查看一下代码如下:
module github/hisheng/protoc-gen-go-struct
go 1.19
2.3 写main函数
咱们在我的项目根目录,写一个main.go如下
touch main.go
此时咱们发现我的项目根目录下,生成了一个main.go文件。
咱们写一个main函数,代码如下:
package main
import (
"google.golang.org/protobuf/compiler/protogen"
)
func main() {
protogen.Options{}.Run(func(gen *protogen.Plugin) error {
for _, f := range gen.Files {
if !f.Generate {
continue
}
generateFile(gen, f)
}
return nil
})
}
这个main()函数大家能够间接复制,根本所有的插件都是这样的格局,当然这个main也能够承受参数,这里咱们简化,先不介绍,感兴趣的人,能够参考protoc-gen-go的main函数来写。
咱们本人写的办法次要是 generateFile(gen, f) 这个函数。
这个函数用来读取.proto文件,并且生产go文件。
2.4 自定义generateFile(gen, f)函数
这个函数全称是 generateFile(gen protogen.Plugin, file protogen.File),承受的两个参数
gen *protogen.Plugin 为生成的插件,次要用来生成go文件
file *protogen.File 为.proto文件对他的file对象
我这里的次要代码是:
// 生成.struct.go文件,参数为 输入插件gen,以及读取的文件file
func generateFile(gen *protogen.Plugin, file *protogen.File) {
filename := file.GeneratedFilenamePrefix + ".struct.go"
g := gen.NewGeneratedFile(filename, file.GoImportPath)
// 输入 package packageName
g.P("package ", file.GoPackageName)
g.P() // 换行
for _, m := range file.Messages {
// 输入 type m.GoIdent struct {
g.P("type ", m.GoIdent, " struct {")
for _, field := range m.Fields {
leadingComment := field.Comments.Leading.String()
trailingComment := field.Comments.Trailing.String()
line := fmt.Sprintf("%s %s `json:\"%s\"` %s", field.GoName, field.Desc.Kind(), field.Desc.JSONName(), trailingComment)
// 输入 行首正文
g.P(leadingComment)
// 输入 行内容
g.P(line)
}
// 输入 }
g.P("}")
}
g.P() // 换行
}
就是如此简略的10几行代码,就能够读取.proto文件,并生成.go文件了。接下来咱们具体的介绍一下外面次要的变量以及对象。
2.4.1 第一步学生成 GeneratedFile 对象
filename := file.GeneratedFilenamePrefix + ".struct.go"
g := gen.NewGeneratedFile(filename, file.GoImportPath)
2.4.2 第二步生成go代码的package
// 输入 package packageName
g.P("package ", file.GoPackageName)
g.P() // 换行
2.4.3 第三步便当proto文件的message
因为咱们这里是找message而后生成struct,所以应用file.Messages来获取所有的message,而后遍历
for _, m := range file.Messages {
// 输入 type m.GoIdent struct {
g.P("type ", m.GoIdent, " struct {")
for _, field := range m.Fields {
leadingComment := field.Comments.Leading.String()
trailingComment := field.Comments.Trailing.String()
line := fmt.Sprintf("%s %s `json:\"%s\"` %s", field.GoName, field.Desc.Kind(), field.Desc.JSONName(), trailingComment)
// 输入 行首正文
g.P(leadingComment)
// 输入 行内容
g.P(line)
}
// 输入 }
g.P("}")
}
这一步代码次要生产go的struct,生成后的样子如下:
type User struct {
// xingming
Name string `json:"name"` // 姓名
// age
Age int64 `json:"age"` // 年龄
}
三、编译插件
咱们把这个代码,在本地编译装置,在我的项目根目录执行go install
go install
此时咱们到本人的GOPATH目录查看是否生成
咱们cd到$GOPATH的bin目录,个别go install装置的命令都在这里
cd $GOPATH/bin && ls -al
咱们看到了 protoc-gen-go-struct 二进制命令。
四、protoc应用protoc-gen-go-struct插件
咱们在其余中央写测试方法,写一个 pt.proto文件
mkdir protoc_struct && cd protoc_struct && touch pt.proto
而后把pt.ptoto外面写入代码
syntax = "proto3";
package pt;
option go_package = "./protoc_struct";
message User {
// xingming
string name = 1;// 姓名
// age
int64 age = 2;// 年龄
}
最初咱们在执行 protoc 命令
protoc --go-struct_out=./ pt.proto
此时咱们发现生产了pt.struct.go文件
文件外面生成的go代码如下
package protoc_struct
type User struct {
// xingming
Name string `json:"name"` // 姓名
// age
Age int64 `json:"age"` // 年龄
}
和下面的.proto文件一一对应。
写到这里,咱们本人写一个go对应的protobuf插件就实现。
本文参加了思否技术征文,欢送正在浏览的你也退出。
发表回复