亲宝软件园·资讯

展开

go微服务效率工具goctl

万俊峰Kevin 人气:1

前言

本文根据安前松的视频分享整理而来,视频回放地址如下:

www.bilibili.com/video/BV1Hr…

一、goctl 的由来

1. goctl 的诞生

goctl 的最早功能是为了解决 GRPC 内网调试问题,大约是在 2019 年,在我们的生产环境中,rpc 是内网隔离的,不可通过外网访问,为了快速去 mock 一些线上 RPC client 的请求,就简单的实现了第一版本的代码生成,主要目的是去访问 RPC Server 做一些调试。

2. 为什么需要 goctl?

3. 怎么理解开发规范?

开发规范,包括编码规范,工程规范,提交规范,代码审核规范,部署规范等等,团队内如果将开发规范统一起来,其收益可想而知,举个例子:假如你所在的公司没有统一开发规范,这时需要你去做一些跨部门协作或者支持,焕然一新的开发环境让你望而却步,还没开始就有了抵触的念头,这岂不是违背了支持的初衷。

4. 怎么理解工程效率?

工程效率,要理解工程效率,可以先看看『效率』的定义:

效率是指单位时间内完成的工作量

效率的目标是快,但快并不是效率,换句话说就是在单位时间内完成的高质量工作,这才是我们要追求的目标,那么工程效率就是为了『缩短从开发到线上的距离』

二 、goctl 的安装及功能介绍

1. 介绍

goctl 发展历史可以大概的过一下,挑几个标志性的功能讲讲吧!

首先是 goctl rpc,goctl rpc 的第一版本就是 goctl 的雏形,主要是为了生成 client 代码对 rpc 做调试使用,具体就不展开了。goctl rpc 的发展经过了很多曲折,印象比较深刻的应该算 goctl rpc proto 向 goctl rpc protoc 的转变,这期间为了解决很多问题,才做了相应的变更,具体细节在分享 rpc 代码生成使用那块再详细分享,在这里面其实对我来说印象最深刻的一个功能算是 goctl model 了,其算是我开始维护 goctl 的一个入手点吧,也是我从业务开发实践中挖掘的解决方案吧,终究我还是比较 "懒",记得在当时开发一个业务模块,由于业务比较大,需要创建的数据表也很多,在没有 goctl 前都是自己去手动编码完成,这一块我记忆犹新,花了仅一天的时间来写 model 文件,因为我没有用 orm 的习惯,所以这块 sql 完全是裸 sql 语句,服务跑起来后才发现有很多 sql 传参上的错误,基本都是多参少参问题,除此之外,每次新增索引,或者字段变更,缓存的相关逻辑维护也让我十分头疼,于是结合当时的开发最佳实践,将其按照缓存与否把这块的工作交给了 goctl,第一版本 goctl model 生成主要是网页版本,后面陆续集成到 goctl 里了,这给我后续开发带来了很大的开发效率收益。

2. 安装

Goctl 安装有两种方式,分别是 go get 或者 go install,其次是 docker。

go get/install

# Go 1.16 之前版本
$ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/go-zero/tools/goctl@latest
# Go 1.16 及以后版本
$ GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest
# macOS
$ brew install goctl
# 验证
$ goctl --version
goctl version 1.3.5 darwin/amd64
# 查看 goctl
$ cd $GOPATH/bin && ls | grep "goctl"

如果执行 goctl --version 提示 command not found: goctl 的错误,请先排查 $GOBIN 是否在环境变量下。

docker

# 1. pull
$ docker pull kevinwan/goctl
....
# 2. ls
$ docker image ls | grep "goctl"
kevinwan/goctl        latest    7fd46843de3d   5 weeks ago    383MB
# 3. run
$ docker run -it kevinwan/goctl /bin/sh

3. 功能介绍

我们接下来看看功能介绍,通过指令 goctl --help 可以列出我们当前已经支持的功能,可能大家在看文档时也没有专心下来对这块指令做研究,只是用到一些高频指令,今天既然是 goctl 的专题分享,我们就花点时间来一起过过,带着大家从 0 到 1 熟悉 goctl。

$ goctl --help                                                       
A cli tool to generate api, zrpc, model code
Usage:
goctl [command]
Available Commands:
api         Generate api related files
bug         Report a bug
completion  Generate the autocompletion script for the specified shell
docker      Generate Dockerfile
env         Check or edit goctl environment
help        Help about any command
kube        Generate kubernetes files
migrate     Migrate from tal-tech to zeromicro
model       Generate model code
quickstart  quickly start a project
rpc         Generate rpc code
template    Template operation
upgrade     Upgrade goctl to latest version
Flags:
-h, --help      help for goctl
-v, --version   version for goctl
Use "goctl [command] --help" for more information about a command.

goctl 的功能比较丰富,所以难免指令参数比较多,大家在使用时除了看文档外,也善用 --help 这个flag,因为他会告诉你每个指令或者子指令的用法,需要什么参数,参数类型是字符串还是布尔,是必填还是可选,切不可自己猜测他应该用什么 flag,虽然 goctl 是我自己主要维护,其实很多时候,有些指令比较文档,没有太多 feature 去更新,我也记不住,我也是通过 --help 去查看功能介绍的

goctl completion

查看 goctl 版本

$ goctl --version
goctl version 1.3.5 darwin/amd64

1.3.5

本节内容仅适合 goctl 版本在 1.3.5及之前的的自动补全设置参考,1.3.5版本及之前仅支持类 Unix 操作系统,不支持 Windows 的自动补全,1.3.5 之后的请跳过此节内容

$ goctl completion --help                                
   NAME:
   goctl completion - generation completion script, it only works for unix-like OS
USAGE:
goctl completion [command options] [arguments...]
OPTIONS:
--name value, -n value  the filename of auto complete script, default is [goctl_autocomplete]

根据帮助说明得知,goctl completion 支持通过 --name 传递一个参数生成自动补全脚本文件名,但该参数为非必填,默认不填时为goctl_autocomplete 文件,其位于 $GOCTLHOME 目录下。

$ goctl completion
generation auto completion success!
executes the following script to setting shell:
echo PROG=goctl source /Users/keson/.goctl/.auto_complete/zsh/goctl_autocomplete >> ~/.zshrc && source ~/.zshrc
# 或者
echo PROG=goctl source /Users/keson/.goctl/.auto_complete/bash/goctl_autocomplete >> ~/.bashrc && source ~/.bashrc
$ echo $SHELL                                                  
/bin/zsh
$ echo PROG=goctl source /Users/keson/.goctl/.auto_complete/zsh/goctl_autocomplete >> ~/.zshrc && source ~/.zshrc
# 键入 goctl 后按下 tab 键查看自动补全提示
$ goctl # tab
api            -- generate api related files
bug            -- report a bug
completion     -- generation completion script, it only works for unix-like OS
docker         -- generate Dockerfile
env            -- check or edit goctl environment
help        h  -- Shows a list of commands or help for one command
kube           -- generate kubernetes files
migrate        -- migrate from tal-tech to zeromicro
model          -- generate model code
rpc            -- generate rpc code
template       -- template operation
upgrade        -- upgrade goctl to latest version

1.3.6

本节内容仅适合 goctl 版本在 1.3.6 及之后的的自动补全设置参考,1.3.6 之前的请跳过此节内容

# 编辑 ~/.zshrc
$ vim ~/.zshrc
# 找到 PROG=goctl 所在行并删除
# source
$ source ~/.zshrc && rm .zcompdump*
# 重启终端
$ goctl completion --help
Generate the autocompletion script for goctl for the specified shell.
See each sub-command's help for details on how to use the generated script.
Usage:
goctl completion [command]
Available Commands:
bash        Generate the autocompletion script for bash
fish        Generate the autocompletion script for fish
powershell  Generate the autocompletion script for powershell
zsh         Generate the autocompletion script for zsh
Flags:
-h, --help   help for completion
Use "goctl completion [command] --help" for more information about a command.
$ echo $SHELL                                                  
/bin/zsh
$ goctl completion zsh --help
Generate the autocompletion script for the zsh shell.
If shell completion is not already enabled in your environment you will need
to enable it.  You can execute the following once:
        echo "autoload -U compinit; compinit" >> ~/.zshrc
To load completions for every new session, execute once:
#### Linux:
        goctl completion zsh > "${fpath[1]}/_goctl"
#### macOS:
        goctl completion zsh > /usr/local/share/zsh/site-functions/_goctl
You will need to start a new shell for this setup to take effect.
Usage:
goctl completion zsh [flags]
Flags:
-h, --help              help for zsh
--no-descriptions   disable completion descriptions

从上文可以看出,根据操作系统的不同,自动补全的设置方式也不一样,我这里是 macOS,我们执行一下对应的指令:

$ goctl completion zsh > /usr/local/share/zsh/site-functions/_goctl

我们先重开一个终端来试一下:

# 键入 goctl 后按下 tab 键查看自动补全提示
$ goctl # tab
api         -- Generate api related files
bug         -- Report a bug
completion  -- Generate the autocompletion script for the specified shell
docker      -- Generate Dockerfile
env         -- Check or edit goctl environment
help        -- Help about any command
kube        -- Generate kubernetes files
migrate     -- Migrate from tal-tech to zeromicro
model       -- Generate model code
quickstart  -- quickly start a project
rpc         -- Generate rpc code
template    -- Template operation
upgrade     -- Upgrade goctl to latest version

常见错误

goctl migrate

帮助开发者从1.3.0 之前版本无缝迁移到 1.3.0及后的任意版本,如果使用的 go-zero 版本本身就是 1.3.0 及之后的,则无需做此操作。

为什么需要迁移?

go-zero 在 1.3.0 版本做了组织变更,即用 zeromicro 替换原来的 tal-tech 组织名称。

我现在有一个演示项目 awesomemigrate 是用旧版本 goctl 生成的,该项目的 go-zero 的 module 为

module awesomemigrate
go 1.18
require github.com/tal-tech/go-zero v1.2.5
...

假设我们需要将该项目的 go-zero 升级至截止目前最新版本 1.3.3 ,要完成项目从 tal-tech 到 zeromicro 的升级 前需要确保 goctl 版本大于 v1.3.2,然后在执行 goctl 迁移指令执行,如果 goctl 版本小于 v1.3.2,则需要升级。

# 1. 查看当前 goctl 版本
$ goctl --version
goctl version 1.2.5 darwin/amd64
# 2. 由于 goctl 版本小于 v1.3.2,则需要升级至最新,如果 goctl 版本已经是1.3.2及之后了,则可以不用升级
$ go install github.com/zeromicro/go-zero/tools/goctl@latest
# 3. 查看一下迁移指令使用帮助
$ goctl migrate --help                                  
NAME:
goctl migrate - migrate from tal-tech to zeromicro
USAGE:
goctl migrate [command options] [arguments...]
DESCRIPTION:
migrate is a transition command to help users migrate their projects from tal-tech to zeromicro version
OPTIONS:
--verbose, -v    verbose enables extra logging
--version value  the target release version of github.com/zeromicro/go-zero to migrate
# 4. 进入待迁移的项目下,执行迁移指令
$ goctl migrate --version 1.3.3
# 5. 验证依赖是否存在问题
$ go test .
?       awesomemigrate  [no test files]

迁移完成后,我们再来看看 module 文件

module awesomemigrate
go 1.18
require github.com/zeromicro/go-zero v1.3.3
...

在 project 搜索一下 tal-tech的匹配结果会发现为0:

goctl env

goctl env 主要是用于环境检测、安装、环境参数控制等功能,除此之外还可以查看当前 goctl 的一些环境信息,以至于用户在遇到 bug 时可以根据此环境上报当前 goctl 处于的环境。

首先我们看看其使用说明

$ goctl env --help                                    
NAME:
goctl env - check or edit goctl environment
USAGE:
goctl env command [command options] [arguments...]
COMMANDS:
install  goctl env installation
check    detect goctl env and dependency tools
OPTIONS:
--write value, -w value  edit goctl environment
--help, -h               show help

goctl env 支持环境查看、参数修改、依赖检测安装几个功能,我们依次来看一下

环境查看

在不输入任何 flag 的情况下,则是查看当前 goctl 环境。

$ goctl env                                             
GOCTL_OS=darwin                        
GOCTL_ARCH=amd64
GOCTL_HOME=/Users/keson/.goctl
GOCTL_DEBUG=false
GOCTL_CACHE=/Users/keson/.goctl/cache
GOCTL_VERSION=1.3.5
PROTOC_VERSION=3.19.4
PROTOC_GEN_GO_VERSION=v1.27.1
PROTO_GEN_GO_GRPC_VERSION=1.2.0

以上参数的大概说明为

参数名称参数类型参数说明
GOCTL_OSSTRING当前操作系统,常见值有 darwin、windows、linux 等
GOCTL_ARCHSTRING当前系统架构,常见值有 amd64, 386 等
GOCTL_HOMESTRING默认为 ~/.goctl
GOCTL_DEBUGBOOLEAN是否开启 debug 模式,默认为 false,目前暂未使用,主要是 goctl 开发中可能用于控制调试模式
GOCTL_CACHESTRINGgoctl 缓存目录,主要缓存下载的依赖 protoc、protoc-gen-go、protoc-gen-go-grpc等
GOCTL_VERSIONSTRING当前 goctl 版本
PROTOC_VERSIONSTRING当前 protoc 版本,如未安装则为空字符串
PROTOC_GEN_GO_VERSIONSTRING当前 protoc-gen-go 版本,如未安装或者从github.com/golang/protobuf 安装版本为 v1.3.2 之前的则为空字符串
PROTO_GEN_GO_GRPC_VERSIONSTRING当前 protoc-gen-go-grpc版本,如未安装则为空字符串

修改参数

比如我们将 GOCTL_DEBUG 修改为 true

# 修改前
$ goctl env | grep 'GOCTL_DEBUG'
GOCTL_DEBUG=false
# 修改 GOCTL_DEBUG 为 true
$ goctl env -w GOCTL_DEBUG=true
# 修改后
goctl env | grep 'GOCTL_DEBUG'
GOCTL_DEBUG=true

依赖检测/安装

我们来检测一下我当前的依赖都是否安装好,目前依赖检测内容为protoc、protoc-gen-go、protoc-gen-go-grpc

# 我们来检查一下依赖安装
$ goctl env check --verbose                              
[goctl-env]: preparing to check env
[goctl-env]: looking up "protoc"
[goctl-env]: "protoc" is not found in PATH
[goctl-env]: looking up "protoc-gen-go"
[goctl-env]: "protoc-gen-go" is not found in PATH
[goctl-env]: looking up "protoc-gen-go-grpc"
[goctl-env]: "protoc-gen-go-grpc" is not found in PATH
[goctl-env]: check env finish, some dependencies is not found in PATH, you can execute
command 'goctl env check --install' to install it, for details, please execute command
'goctl env check --help'
# 安装依赖,安装依赖有2中方式
# 方式一
# $ goctl env check --install --force --verbose
# 方式二
$ goctl env install --verbose -f                       
[goctl-env]: preparing to check env
[goctl-env]: looking up "protoc"
[goctl-env]: "protoc" is not found in PATH
[goctl-env]: preparing to install "protoc"
[goctl-env]: "protoc" is already installed in "/Users/keson/go/bin/protoc"
[goctl-env]: looking up "protoc-gen-go"
[goctl-env]: "protoc-gen-go" is not found in PATH
[goctl-env]: preparing to install "protoc-gen-go"
[goctl-env]: "protoc-gen-go" is already installed in "/Users/keson/go/bin/protoc-gen-go"
[goctl-env]: looking up "protoc-gen-go-grpc"
[goctl-env]: "protoc-gen-go-grpc" is not found in PATH
[goctl-env]: preparing to install "protoc-gen-go-grpc"
[goctl-env]: "protoc-gen-go-grpc" is already installed in "/Users/keson/go/bin/protoc-gen-go-grpc"
[goctl-env]: congratulations! your goctl environment is ready!

goctl rpc

首先我们来看一下该指令的使用帮助

goctl rpc -h                                                       
Generate rpc code
Usage:
goctl rpc [flags]
goctl rpc [command]
Available Commands:
new         Generate rpc demo service
protoc      Generate grpc code
template    Generate proto template
Flags:
--branch string   The branch of the remote repo, it does work with --remote
-h, --help            help for rpc
--home string     The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority
--o string        Output a sample proto file
--remote string   The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority
The git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure
Use "goctl rpc [command] --help" for more information about a command.

该指令提供了三个子指令,new 是快速创建一个 zrpc 服务,protoc 是根据 proto 描述文件生成 zrpc 代码,而 template 则是快速生成一个 proto 模板,我们将重点围绕 goctl rpc protoc 指令来展开,看看 goctl rpc protoc 的使用说明:

goctl rpc protoc -h                                              
Generate grpc code
Usage:
goctl rpc protoc [flags]
Examples:
goctl rpc protoc xx.proto --go_out=./pb --go-grpc_out=./pb --zrpc_out=.
Flags:
--branch string     The branch of the remote repo, it does work with --remote
-h, --help              help for protoc
--home string       The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority
--remote string     The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority
The git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure
--style string      The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md] (default "gozero")
-v, --verbose           Enable log output
--zrpc_out string   The zrpc output directory

goctl rpc protoc 到底怎么使用,为什么示例里面有 --go_out、--go-grpc_out 参数,而查看 help 的时候却没有看到介绍?目前我们先这样理解,我们先抛开 goctl,根据官方 protoc 生成 grpc 代码时的指令是什么?会用到哪些 flag,对于 zrpc 的代码生成,你可以理解为 goctl 生成 zrpc 只是在生成 grpc 代码指令的基础上加了 goctl rpc 前缀和一些 goctl 生成 zrpc 需要的 flag,而对于 protoc 及 插件 protoc-gen-go 、 protoc-gen-grpc-go 的相关参数 goctl 只是做继承,没有必要显示的在 help 里面再描述一遍,后面在分析源码时可以给大家详细讲解一些这块的设计和考虑,接下来我们用一个例子来演示一下,假设我们有一个 greet.proto 文件,抛开 goctl ,我们生成 grpc 代码需要执行的指令如下:

如果不知道 grpc 代码是怎么生成的,这块建议参考官方文档 grpc.io/

# 进入 greet.proto 所在目录
$ protoc greet.proto --go_out . --go-grpc_out .
$ tree
.
├── greet.proto
└── pb
├── greet.pb.go
└── greet_grpc.pb.go

那么按照上文对 goctl rpc protoc 的介绍,我们生成 zrpc 代码的指令则应该为

# 这里多了一个 --zrpc_out 用于指定 zrpc 代码的输出目录
$ goctl rpc protoc greet.proto --go_out=. --go-grpc_out=. --zrpc_out=. --verbose
[goctl-env]: preparing to check env
[goctl-env]: looking up "protoc"
[goctl-env]: "protoc" is installed
[goctl-env]: looking up "protoc-gen-go"
[goctl-env]: "protoc-gen-go" is installed
[goctl-env]: looking up "protoc-gen-go-grpc"
[goctl-env]: "protoc-gen-go-grpc" is installed
[goctl-env]: congratulations! your goctl environment is ready!
[command]: protoc greet.proto --go_out . --go-grpc_out .
Done.
$ tree
.
├── etc
│   └── greet.yaml
├── go.mod
├── greet
│   └── greet.go
├── greet.go
├── greet.proto
├── internal
│   ├── config
│   │   └── config.go
│   ├── logic
│   │   └── pinglogic.go
│   ├── server
│   │   └── greetserver.go
│   └── svc
│       └── servicecontext.go
└── pb
├── greet.pb.go
└── greet_grpc.pb.go
8 directories, 11 files

如果在生成代码时需要输出日志,可以加 --verbose 来显示日志。

goctl rpc protoc 在生成 zrpc 代码时会先对你的环境依赖进行检测,如果没有安装则会自动安装依赖再生成代码。

编辑器插件

为了提升大家对 zero-api 文件的编写效率,我们分别对 intellij 和 vscode 提供了相应的编辑器插件, vscode 插件介绍及使用请参考 github.com/zeromicro/g…

三、goctl 使用中遇到的问题

goctl 从最初的一个功能 rpc proxy 到当前版本(v1.3.5) 已经拥有13个一级指令和近30个二级指令, 期间 goctl 做了一些调整,而且,gcotl 本身的前进步伐也非常快,他更像是在摸索中前进,朝着更快,更好用的方向发展,因此在迭代的路上,goctl 会显得有些不稳定,大家兴许也遇到很多问题,这里大概总结一下大家在社区中反馈比较多的一些问题来分享一下。

1. 386 架构上安装 goctl 失败!

描述:antlr 生成的源码中,没有对 386 架构的 uint 的边界值进行很好的处理,导致边界溢出

修复版本:v1.3.3

2. grpc 到底安装什么版本插件?

描述:熟悉 grpc 的人应该都知道,生成 grpc 代码的插件 protoc-gen-go 有两个仓库在维护,有3 个安装来源,2个维护仓库分别是:

# 1. golang
# github.com/golang/protobuf/protoc-gen-go
# 2. protocolbuffers
# github.com/protocolbuffers/protobuf-go/cmd/protoc-gen-go

三个安装来源是

# 1. golang 维护的仓库,目前已不推荐使用
# github.com/golang/protobuf/protoc-gen-go
# 2. protocolbuffers 维护的,目前推荐使用的
# github.com/protocolbuffers/protobuf-go/cmd/protoc-gen-go
# 3. goolge 安装,这其实和第二种安装的是一个二进制,他的源码就是protocolbuffers 维护的相同仓库
# google.golang.org/protobuf/cmd/protoc-gen-go

在 v.1.3.4前,如果使用 goctl rpc proto 生成 zrpc 代码则建议安装旧版本的插件,即 golang 维护的,因此该指令生成 zrpc 代码是 goctl 为了用户生成指令的简单,做了很厚的封装,但随之带来的问题就是难兼容,因此该指令已不推荐使用。

在v.1.3.4及以后,没有对 protoc-gen-go 做限制,用户可以自由选择不同的来源进行安装,但建议还是安装 protocolbuffer 维护的版本(官方文档已经替换为这个),而且必须要安装protoc-gen-grpc-go 插件,这样做的目的是跟着 grpc 官方走,不过用户不用有太大的心理负担,一下安装这么多依赖,很麻烦,goctl 都已经帮你实现了,你只要使用 goctl rpc protoc 生成代码时会自动检测依赖并安装。

综上所述,建议大家还在使用该指令的用户尽早用 goctl rpc protoc 替代。

3. 错误提升

为什么 Windows 上生成 api/zrpc 代码时,总是提示 The system cannot find the path specified 类似错误?

goctl.exe api go -api test.api -dir .
Stat : The system cannot find the path specified.

描述:产生该原因是因为 go list -json -m 获取 go module 时拿到的是一个固定值command-line-arguments,该问题已经在 github.com/zeromicro/g… 进行修复,版本将在 v1.3.6 生效。

4. No help topic 'proto'

描述:该指令在 v1.3.4 已经移除,用 goctl rpc protoc 替代

5. zrpc 生成代码时报 go_package 错误

protoc-gen-go: unable to determine Go import path for "greet.proto"
Please specify either:
• a "go_package" option in the .proto source file, or
• a "M" argument on the command line.
See https://developers.google.com/protocol-buffers/docs/reference/go-generated#package for more information.
--go_out: protoc-gen-go: Plugin failed with status code 1.

6. zrpc 生成代码时指定了 pb 的输出目录为当前服务 main 目录

the output of pb.go and _grpc.pb.go must not be the same with --zrpc_out:
pb output: /Users/keson/workspace/awesome-goctl/zwesome-zrpc/pb_in_main
zrpc out: /Users/keson/workspace/awesome-goctl/zwesome-zrpc/pb_in_main

7. 为什么我的代码生成的 pb client(不)带 client 标志?

这是旧版本 goctl rpc proto 生成 zrpc 代码时才有这个问题,目前已经移除了该指令。

8. 为什么我生成的目录结构和文档演示不一样?

对于 goctl rpc protoc 生成 zrpc 代码的目录结构,总的结构上是不会存在差异的,唯一存在差异的是 pb 的输出目录,这个取决于你指定的参数来控制,控制 pb 输出目录的因素有 go_optgo-grpc_optgo_package

9. 为什么我安装了 goctl 编辑器插件还是不能高亮

打开 Goland 的设置,搜索 FileTypes 设置 api 文件后缀即可。

项目地址 github.com/zeromicro/g…

加载全部内容

相关教程
猜你喜欢
用户评论