• go generate


    介绍

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

    有几点需要注意:

    • 该特殊注释必须在 .go 源码文件中。
    • 每个源码文件可以包含多个 generate 特殊注释时。
    • 显示运行 go generate 命令时,才会执行特殊注释后面的命令。
    • 命令串行执行的,如果出错,就终止后面的执行。
    • 特殊注释必须以 //go:generate 开头,双斜线后面没有空格。

    应用

    在有些场景下,我们会使用 go generate

    • yacc:从 .y 文件生成 .go 文件。
    • protobufs:从 protocol buffer 定义文件(.proto)生成 .pb.go 文件。
    • Unicode:从 UnicodeData.txt 生成 Unicode 表。
    • HTML:将 HTML 文件嵌入到 go 源码 。
    • bindata:将形如 JPEG 这样的文件转成 go 代码中的字节数组。

    再比如:

    • string方法:为类似枚举常量这样的类型生成String()方法。
    • 宏:为既定的泛型包生成特定的实现,比如用于ints的sort.Ints。

    命令

    go generate 命令使用格式如下:

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

    其中:

    • -run 正则表达式匹配命令行,仅执行匹配的命令
    • -v 输出被处理的包名和源文件名
    • -n 显示不执行命令
    • -x 显示并执行命令

    执行 go generate 时,有一些环境变量可以使用:

    $GOARCH
        体系架构 (arm、amd64等待)
    $GOOS
        OS环境(linux、windows等)
    $GOFILE
        当前处理中的文件名
    $GOLINE
        当前命令在文件中的行号
    $GOPACKAGE
        当前处理文件的包名
    $DOLLAR
        固定的"$",不清楚用途
    

    假设我们有个main.go文件,内容如下:

    package main
    
    import "fmt"
    
    //go:generate echo hello
    //go:generate go run main.go
    //go:generate  echo file=$GOFILE pkg=$GOPACKAGE
    func main() {
        fmt.Println("main func")
    }
    

    执行 go generate 后,输出如下:

    $ go generate
    hello
    main func
    file=main.go pkg=main
    

    示例

    现在我们来实践一下前面介绍的 go generate

    String()方法

    假设我们有一些代码,里面包含若干定义为Pill的整型常量:

    package painkiller
    
    type Pill int
    
    const (
        Placebo Pill = iota
        Aspirin
        Ibuprofen
        Paracetamol
        Acetaminophen = Paracetamol
    )
    

    为了调试的需要,我们会为这些常量定义String()签名方法:
    func (p Pill) String() string

    一般情况下,我们可能会像下面这样写:

    func (p Pill) String() string {
        switch p {
        case Placebo:
            return "Placebo"
        case Aspirin:
            return "Aspirin"
        case Ibuprofen:
            return "Ibuprofen"
        case Paracetamol: // == Acetaminophen
            return "Paracetamol"
        }
        return fmt.Sprintf("Pill(%d)", p)
    }
    

    这里,我们可以用 go generate 来实现String():

    首先,我这里创建一个painkiller.go文件,包含如下内容:

    //go:generate stringer -type=Pill
    package painkiller
    
    type Pill int
    
    const (
        Placebo Pill = iota
        Aspirin
        Ibuprofen
        Paracetamol
        Acetaminophen = Paracetamol
    )
    

    在文件的开头包含了一个 //go:generate stringer -type=Pill 特殊注释,其中stringer是个生成String方法的工具,为了使用stringer方法,在运行 go generate 命令前,我们需要安装stringer工具,命令如下:

    $ go get golang.org/x/tools/cmd/stringer
    

    然后,在 painkiller.go 所在的目录下面运行 go generate 命令:

    $ go generate
    

    我们会发现当前目录下面生成一个pill_string.go文件,里面实现了我们需要的String()方法,文件内容如下:

    // Code generated by "stringer -type=Pill"; DO NOT EDIT.
    
    package painkiller
    
    import "fmt"
    
    const _Pill_name = "PlaceboAspirinIbuprofenParacetamol"
    
    var _Pill_index = [...]uint8{0, 7, 14, 23, 34}
    
    func (i Pill) String() string {
        if i < 0 || i >= Pill(len(_Pill_index)-1) {
            return fmt.Sprintf("Pill(%d)", i)
        }
        return _Pill_name[_Pill_index[i]:_Pill_index[i+1]]
    }
    
  • 相关阅读:
    Socket经验记录
    有了WCF,Socket是否已人老珠黄?
    更新Svn客户端后,右键菜单中没有TortoiseSVN了
    线程已被中止 “Thread was being aborted”
    c# 温故而知新: 线程篇(一)
    SOCKET是多线程安全的吗? [问题点数:40分,结帖人CSDN]
    <base href=""/> 的应用
    Python Twisted 框架中 socket通信
    本人作品-〉VPS应用>Discuz网页斗地主插件
    浅析 c# Queue
  • 原文地址:https://www.cnblogs.com/niuben/p/15578261.html
Copyright © 2020-2023  润新知