go generate 的用法_go:generate_raoxiaoya的博客-程序员秘密

技术标签: golang  

概述

golang tools 是官方提供的工具集,是 Gophers 的工具宝库,值得好好探索一番,参见 GitHub文档地址。里面有丰富的开发辅助工具,所有的 Go 开发插件都离不开这些工具的支持。例如goimports工具自动导入使用的包,去掉未使用的包;gorename用来重命名标识符。

今天要使用的stringer工具也在tools工具包中。

命令描述如下:

go help generate

usage: go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]

Generate runs commands described by directives within existing
files. Those commands can run any process but the intent is to
create or update Go source files.

Go generate is never run automatically by go build, go get, go test,
and so on. It must be run explicitly.

Go generate scans the file for directives, which are lines of
the form,

        //go:generate command argument...

(note: no leading spaces and no space in "//go") where command
is the generator to be run, corresponding to an executable file
that can be run locally. It must either be in the shell path
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
command alias, described below.

...

总的说来 go generate 允许你在 go 代码中来运行当前系统中已安装的程序,原则上你可以运行任何程序,但是此命令设计的初衷是用来创建或者更新go源码文件。
如果要执行的程序不在环境变量中,则需要写全路径。
必须手动执行 go generate,才会去解析执行 generate 指令,并且 go generate 命令不会执行go源代码。
单个运行只需要在对应目录(包)下执行:go generate
对应有多个目录,且又有多个generate需要执行的,在最上层目录下运行:go generate ./…

一个简单的例子:

package main

import "fmt"

//go:generate echo hello

func main() {
    
	fmt.Println("Hello world!")
}

在linux系统上运行 go generate
输出 hello
就相当于你直接运行 echo hello

go generate命令是go 1.4版本里面新添加的一个命令,当运行go generate时,它将扫描与当前包相关的源代码文件,找出所有包含"//go:generate"的特殊注释,提取并执行该特殊注释后面的命令,命令为可执行程序,形同shell下面执行。

使用场景

  1. 在build之前生成一些特定文件(下文介绍)。
  2. yacc:从 .y 文件生成 .go 文件。
  3. protobufs:从 protocol buffer 定义文件(.proto)生成 .pb.go 文件。
  4. Unicode:从 UnicodeData.txt 生成 Unicode 表。

注意事项

  1. 必须在.go源码文件中。
  2. 每个源码文件可以包含多个generate特殊注释。
  3. 显示运行go generate命令时,才会执行特殊注释后面的命令。
  4. 如果前面的注释执行出错,则终止执行。
  5. //与go:generate之间不能有空格。

可以使用的环境变量

$GOARCH:体系架构 (arm、amd64等)
$GOOS:OS环境(linux、windows等)
$GOFILE:当前处理中的文件名
$GOLINE:当前命令在文件中的行号
$GOPACKAGE:当前处理文件的包名
$DOLLAR:美元符号

在开发API Server的时候我们需要去定义一些错误码及其描述,每次定义错误码的时候,同时需要添加描述信息。而且描述信息经常会忘。比如:
errcode.go

package main

type ErrCode int

//go:generate stringer -type ErrCode
const (
	ERR_CODE_OK             ErrCode = 0 // OK
	ERR_CODE_INVALID_PARAMS ErrCode = 1 // 无效参数
	ERR_CODE_TIMEOUT        ErrCode = 2 // 超时
)

func main() {
    
	fmt.Println(ERR_CODE_INVALID_PARAMS)
}

然后我想使用 go generate 来替我生成描述文件。

安装 stringer 程序:go get golang.org/x/tools/cmd/stringer

stringer命令可以为给定类型生成String方法。

stringer有两种模式,默认是根据变量/常量名来生成字符串描述。我们在常量定义上增加注释:

//go:generate stringer -type ErrCode

选项-type指定stringer命令作用的类型名。

然后在同一个目录下执行:
go generate

会在同一个目录下生成一个文件 errcode_string.go 文件名格式是类型名小写 _string.go。也可以通过 -output 选项指定输出文件名,例如下面就是指定输出文件名为 code_string.go

//go:generate stringer -type ErrCode -output code_string.go

我们来看看这个文件的内容:

// Code generated by "stringer -type ErrCode"; DO NOT EDIT.

package main

import "strconv"

func _() {
    
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{
    }
	_ = x[ERR_CODE_OK-0]
	_ = x[ERR_CODE_INVALID_PARAMS-1]
	_ = x[ERR_CODE_TIMEOUT-2]
}

const _ErrCode_name = "ERR_CODE_OKERR_CODE_INVALID_PARAMSERR_CODE_TIMEOUT"

var _ErrCode_index = [...]uint8{
    0, 11, 34, 50}

func (i ErrCode) String() string {
    
	if i < 0 || i >= ErrCode(len(_ErrCode_index)-1) {
    
		return "ErrCode(" + strconv.FormatInt(int64(i), 10) + ")"
	}
	return _ErrCode_name[_ErrCode_index[i]:_ErrCode_index[i+1]]
}

因为 fmt 包中的很多方法会自动优先调用 String() 方法,所以 fmt.Println(ERR_CODE_INVALID_PARAMS) 将会输出 1,但是我们想要的是后面的注释文本,修改指令
//go:generate stringer -type ErrCode -linecomment

调用 go generate 重新生成

// Code generated by "stringer -type ErrCode -linecomment"; DO NOT EDIT.

package main

import "strconv"

func _() {
    
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{
    }
	_ = x[ERR_CODE_OK-0]
	_ = x[ERR_CODE_INVALID_PARAMS-1]
	_ = x[ERR_CODE_TIMEOUT-2]
}

const _ErrCode_name = "OK无效参数超时"

var _ErrCode_index = [...]uint8{
    0, 2, 14, 20}

func (i ErrCode) String() string {
    
	if i < 0 || i >= ErrCode(len(_ErrCode_index)-1) {
    
		return "ErrCode(" + strconv.FormatInt(int64(i), 10) + ")"
	}
	return _ErrCode_name[_ErrCode_index[i]:_ErrCode_index[i+1]]
}

此时 fmt.Println(ERR_CODE_INVALID_PARAMS) 将会输出 无效参数,符合预期。

生成的代码做了一些优化,减少了字符串对象的数量。

现在你就不用担心添加了错误码而忘记添加错误信息了。

每次编译都需要先运行 go generate 貌似有点麻烦,可以写到 shell 文件。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/raoxiaoya/article/details/111697529

智能推荐

react-dnd 最简单易懂的列表排序_react-dnd 列表排序_谢阳光Zzz的博客-程序员秘密

import React, { Component } from 'react'import { DndProvider, DragSource, DropTarget } from 'react-dnd'import HTML5Backend from 'react-dnd-html5-backend'// 被拖拽的项const source = { // 卡片开始被拖拽时触发 ...

51单片机初级之KeilC51新建工程[1]_robinjr的博客-程序员秘密

1.新建一个DEMO文件夹2.KeilC51中点击新建文件3.命名工程,并保存到DEMO文件夹中4.选择芯片设备(我们选择AT89C52芯片) 5.添加启动文件(STARTUP.A51) 6.整个工程建好了,但是这个时候工程没有东西,需要添加文件 7.新建main.c文件7.1点击左上方新建文件图标(或者使用快捷键CTRL+N) 7.2出现一个不知名的Text1文件 7.3保存该Text1

树莓派 —— 配置Windows通过VNC连接树莓派_信必诺的博客-程序员秘密

VNC简介     VNC (Virtual Network Console)是虚拟网络控制台的缩写。它 是一款优秀的远程控制工具软件,由著名的 AT&amp;T 的欧洲研究实验室开发的。VNC 是在基于 UNIX 和 Linux 操作系统的免费的开源软件,远程控制能力强大,高效实用,其性能可以和 Windows 和 MAC 中的任何远程控制软件媲美。     在 Linux 中,VNC 包括以下四个命令:vncserver,vncviewer,vncpasswd,和 vncconnect。大多数情况下

适配器模式_睡不够的kira的博客-程序员秘密

                                                        适配器模式( adater)1目的:将一个类的接口转化成客户类所需要的接口,使原本因为接口不兼容而不能一起工作的类能够一起给on工作.2适配器的分类:对象适配器和类适配器(通过多继承对一个接口和另外一个接口适配),java因为只支持单继承,所以这里只讲对象适配器. 3何时...

NanoPC T4开发板系列-Android10编译&烧写_nanopct4刷机android_ytuglt的博客-程序员秘密

1.编译系统1,环境要求:Ubuntu18,磁盘空间必须保证139G以上,因为编译完成后查看目录大小为139G,开始在一个空间小的电脑上编译,会发现一直报错,换大空间就好了具体编译可以参考友善wiki:https://wiki.friendlyarm.com/wiki/index.php/NanoPC-T4/zh#.E7.BC.96.E8.AF.91Android10.E6.BA.90.E4.BB.A3.E7.A0.81如文档所示,安装好工具依赖我是按照如图框出来的编译的,正常会执行编译,编译

PyQT5 (二十一) 颜色对话框 QColorDialog 的案例设置控件前景色和背景色_qcolorbutton_ggome的博客-程序员秘密

颜色对话框 QColorDialog 的案例import sysfrom PyQt5.QtCore import Qt, QRegExpfrom PyQt5.QtGui import QIcon, QFont, QPalette, QPixmap, QIntValidator, QDoubleValidator, QRegExpValidatorfrom PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QToolTi...

随便推点

安卓内录声音软件scr_那款安卓手机软件可以内录视频?_自然语言处理老白的博客-程序员秘密

ScreenCam v2.0.3 开源还免费,你说香不香。但是英文的。安装条件:安卓,且已root正在使用中,可以实现内录。内录的时候,是听不到扬声器声音的。找了n多app,目前只有ScreenCam可以内录。时长方面,目前一般录1小时左右,没有问题。再长的没试过。看教程说,需要装一个magisk模块。按照提示下载后刷入,但没成功,如图。我系统环境是 类原生lineageos16 +Magisk2...

was配置虚拟主机_was服务器 如何使用命令设置虚拟主机_songfelicity的博客-程序员秘密

配置用户自己的新的虚拟主机,同时部署一个新的应用使用自己建立的虚拟主机和端口。部署在WAS的应用默认使用9080端口访问,我们此次实验目的是让应用使用9081端口进行应用访问。一、建立一个新的虚拟主机 1、在WAS控制台中依次单击“环境”-》“虚拟主机”​​2、在虚拟主机页面中你会看到WAS环境中已经存在了两个虚拟主机,其中虚拟主机“admin-host”是管理控制台应用使用的,“...

[IDEA 2021] IDEA2021 安装、配置、常用快捷键,Double Shift ,禁用Shift Shift_yjr-1100的博客-程序员秘密

IDEA2021 的安装,常用配置包括(自动导包,字体,模板注释,编码设置,文件头信息),常用快捷键(Double shift,禁用/修改两个shift,Alt+Enter 万能快捷键,自动生成setter和getter方法)

写在前面的一些话:《Learning OpenCV》中文版_hunnish的博客-程序员秘密

 <!--v/:* {behavior:url(#default#VML);}o/:* {behavior:url(#default#VML);}w/:* {behavior:url(#default#VML);}.shape {behavior:url(#default#VML);}--> Normal 0

华为手机NFC功能,教你一键复制各种卡_数据蛙苹果恢复专家的博客-程序员秘密

我们经常会携带各种卡,比如:公交卡、门禁卡、银行卡等,但是忘记带了或者弄不见了该怎么办?点击这篇文章,让小编告诉你华为手机NFC功能的3大作用,让你一键复制各种卡!

Hive权限之改进_ImproveJin的博客-程序员秘密

不足即使开启hive权限认证的情况下,任何用户仍然是超级用户,可以通过grant给任何人赋予任何权限,这样权限认证基本没有意义,因此必须在开启权限认证的同时,对执行grant/revoke的实体进行限制,比如只有admin才能 grant privilege on database,只有table owner才能grant privilege on table。BIP中hive目前是没有开

推荐文章

热门文章

相关标签