### protobuf文件编写在goland gomod下正确姿势探究,由浅入深版(版本proto3)
------
#### 测试环境准备
1. protoc执行文件
https://github.com/protocolbuffers/protobuf/releases/tag/v3.12.3
2. protoc-gen-go
**go get github.com/golang/protobuf/{proto,protoc-gen-go}**
![12313](https://img-blog.csdnimg.cn/20200618035825199.png)
3. 启动GOLAND 创建**go module**项目
#### proto文件名,package与option go_package
###### 单文件测试
文件名,package,以及option go_package对生成文件内容的影响
1. 编写proto文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618035903604.png)
2. 使用命令 `protoc -I . --go_out=. test.proto` 生成.go文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618035921258.png)
3. 修改proto文件,增加package项 `package`
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618035936457.png)
4. 使用命令 `protoc -I . --go_out=. test.proto` 生成.go文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618035948808.png)
5. 再次修改proto文件,增加 `option go_package`项
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040000144.png)
6. 使用命令 `protoc -I . --go_out=. test.proto` 生成.go文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040011428.png)
结论
> 作用 **option go_package > package > 文件名** 对 生成go文件package内容的影响,其中proto文件名还影响最终生成go文件名。
更多的package,以及option go_package内容如何影响到最终生成go文件package内容
1. 移除`option go_package`,修改 `package` 内容为 `package test1.test2;` *(tip:package内容不能使用目录分隔符)*
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040026286.png)
2. 使用命令 `protoc -I . --go_out=. test.proto` 生成.go文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040037407.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
**最终生成的go文件package为proto文件声明的package . 转换 _连接形式**
3. 增加 `option go_package` 选项
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040053868.png)
4. 同样生成
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040103445.png)
**嗯,和package效果类似**
5. 那如果这样呢,使用目录分隔符
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040114999.png)
6. 同样使用命令 ``protoc -I . --go_out=. test.proto``
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040126407.png)
此时结果和之前大有不同
1. 命令根据 `option go_package` 设置的内容在`protoc --go_out=指定的目录(这个可以去测试)`下创建了目录结构 `test3/test4`
2. 最终生成的文件放在 `test3/test4`目录下,并且使用`test4作为go文件package名`
3. 那 这么看 `package`好像已经没什么鸟用了?
###### 多文件引用测试
> 准备
>
> 1. 可选: 在GOLAND中安装protobuf语法提示插件
>
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040145420.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
>
> 2. 修改`test.proto`文件,增加`message`
>
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040157475.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
本地多文件引用测试
1. 增加`test2.proto`文件,并填入如下内容
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040208594.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
**发现在语法提示插件并不能识别到本地的proto文件包含,缺少语法提示**
解决: **GOLAND->设置->搜索protobuf**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040220315.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
完成上述过后
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040230886.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040239492.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
**发现proto文件的`package`还是有用的,在proto文件相互引用时,可以充当`命名空间`的作用**
2. 使用命令 `protoc -I . --go_out=. test2.proto`
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040251242.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
清晰版:![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040303317.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
目录结构生成和之前类似 **go文件包引用采用的是 被引用proto文件的`option go_package`选项内容**
3. 继续,移动`test.proto`文件到目录`randomDir`下
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040315562.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
4. 再次打开`test2.proto`文件,发现语法`报错`
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040325454.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
5. 修正语法错误
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040334535.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
6. 使用命令 `protoc -I . --go_out=. test2.proto`
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040343718.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
结果未变
到这里总结一下吧
> 1. proto文件引入是从某些配置的目录下进行文件查找定位
>
> 如果是语法检查器,则按上面修改GOLAND protobuf相关配置添加相应目录即可
>
> 如果是protoc命令工具,则添加 `-I` 选项指定目录
>
> 2. 一旦多个proto文件被正确import,后面实际在使用的过程中,proto文件的`package`选项可作为`命名空间`使用来区分究竟引用的是`哪个proto文件`的`哪个message`。
*不过上面操作产生的go文件并不能正常运作,正常情况下不同目录的包引用应该是从$GOPATH目录往下*
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040358363.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
------
**上面说了那么多,现在给出一个GOLANG编写proto文件的正确姿势**
> 1. GOLAND新建GO MODULE项目,修改项目设置(`不使用语法提示可以不设置`)
>
>![在这里插入图片描述](https://img-blog.csdnimg.cn/2020061804044412.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
>
> 2. 按照项目需求在不同目录下编写proto文件,但`option go_package`要使用`以项目名开始的目录分隔形式`, `package`用作`命名空间`,可以按需命名
>
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040457457.png)
>
> 3. 使用`protoc命令`生成go文件按如下格式编写
>
> ```shell
> # 前提,protoc命令执行目录是项目目录
>
> protoc -I .. -I . [其他选项] --go_out=.. [如果还有micro --micro_out=..] (proto文件路径)
>
> 比如,上述生成p1.proto文件
> protoc -I .. -I . --go_out=.. dir1/p1.proto
> ```
>
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040510217.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
>
> tips: 还可以利用find命令一次将项目目录下的所有proto文件全部生成
>
> `find ./ -type f -name '*proto' -exec protoc -I .. -I . --go_out=.. {} \;`
------
**有时候我们还需要引用到某些框架下面已经写好的proto文件,在go module上操作简直一堆幺蛾子,目前有一个解决方案**
下面拿引入`github.com/micro/go-micro/v2/api/proto`来说明
1. 执行 `go mod vendor`,项目目录下将生成**vendor文件夹**
2. 设置语法提示(可选):
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040536513.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
3. 编写proto文件引入外部框架的proto文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040655677.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
4. 生成脚本添加 `-I ./vendor/`即可,`protoc -I .. -I . -I ./vendor --go_out=.. test.proto`
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200618040715851.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N3aWZ0bGM=,size_16,color_FFFFFF,t_70)
*一切工作正常! 唉,坑啊*
有疑问加站长微信联系(非本文作者))