解释在这个例子中生成

时间:2016-05-21 11:01:39

标签: go

我很难理解go generate。我也发现几乎没有关于go generate的帖子。

请在以下示例中解释go generate

package main

import (
        "gopkg.in/mgo.v2"
        "gopkg.in/mgo.v2/bson"
)

// --- Address

type Address struct {
        Id            bson.ObjectId `bson:"_id,omitempty"`
        AccountId     string        `bson:"account_id"`
        Name          string        `bson:"name"`
        StreetAddress string        `bson:"streetaddress"`
        Town          string        `bson:"town"`
        Country       string        `bson:"country"`
}

// --- AddressHandler

type AddressHandler struct {
        MS *mgo.Session
}

func NewAddressHandler(ms *mgo.Session) *AddressHandler {
        return &AddressHandler{MS: ms.Clone()}
}

func (h *AddressHandler) Close() {
        h.MS.Close()
}

// Add

type AddAddressInput struct {
        Address *Address
}

type AddAddressOutput struct {
        Error error
}

func (h *AddressHandler) AddAddress(in *AddAddressInput, out *AddAddressOutput) {
        ms := h.MS.Copy()
        defer ms.Close()
        c := ms.DB("").C("address")
        out.Error = c.Insert(in.Address)
}

// Remove

type RemoveAddressInput struct {
        AddressId string
}

type RemoveAddressOutput struct {
        Error error
}

func (h *AddressHandler) RemoveAddress(in *RemoveAddressInput, out *RemoveAddressOutput) {
        ms := h.MS.Copy()
        defer ms.Close()
        c := ms.DB("").C("address")
        out.Error = c.RemoveId(bson.ObjectIdHex(in.AddressId))
}

// Update

type UpdateAddressInput struct {
        Address *Address
}

type UpdateAddressOutput struct {
        Error error
}

func (h *AddressHandler) UpdateAddress(in *UpdateAddressInput, out *UpdateAddressOutput) {
        ms := h.MS.Copy()
        defer ms.Close()
        c := ms.DB("").C("address")
        out.Error = c.UpdateId(in.Address.AccountId)
}

// GetAllByAccount

type GetAddressInput struct {
        AccountId string
}

type GetAddressOutput struct {
        Address []*Address
        Error   error
}

func (h *AddressHandler) GetAddress(in *GetAddressInput, out *GetAddressOutput) {
        ms := h.MS.Copy()
        defer ms.Close()
        c := ms.DB("").C("address")
        out.Error = c.Find(bson.ObjectIdHex(in.AccountId)).All(&out.Address)
}

我想创建这个尚未模板代码的几乎副本。

"模板"代码:

package main

import (
        "gopkg.in/mgo.v2"
        "gopkg.in/mgo.v2/bson"
)

// --- Address

type %Model% struct {
        Id            bson.ObjectId `bson:"_id,omitempty"`
}

// --- %Model%Handler

type %Model%Handler struct {
        MS *mgo.Session
}

func New%Model%Handler(ms *mgo.Session) *%Model%Handler {
        return &%Model%Handler{MS: ms.Clone()}
}

func (h *%Model%Handler) Close() {
        h.MS.Close()
}

// Add

type Add%Model%Input struct {
        %Model% *%Model%
}

type Add%Model%Output struct {
        Error error
}

func (h *%Model%Handler) Add%Model%(in *Add%Model%Input, out *Add%Model%Output) {
        ms := h.MS.Copy()
        defer ms.Close()
        c := ms.DB("").C("%Model%")
        out.Error = c.Insert(in.%Model%)
}

// Remove %Model%

type Remove%Model%Input struct {
        %Model%Id string
}

type Remove%Model%Output struct {
        Error error
}

func (h *%Model%Handler) Remove%Model%(in *Remove%Model%Input, out *Remove%Model%Output) {
        ms := h.MS.Copy()
        defer ms.Close()
        c := ms.DB("").C("%Model%")
        out.Error = c.RemoveId(bson.ObjectIdHex(in.%Model%Id))
}

// Update

type Update%Model%Input struct {
        %Model% *%Model%
}

type Update%Model%Output struct {
        Error error
}

func (h *%Model%Handler) Update%Model%(in *Update%Model%Input, out *Update%Model%Output) {
        ms := h.MS.Copy()
        defer ms.Close()
        c := ms.DB("").C("%Model%")
        out.Error = c.UpdateId(in.%Model%.AccountId)
}

// GetAllByAccount

type Get%Model%Input struct {
        AccountId string
}

type Get%Model%Output struct {
        %Model% []*%Model%
        Error   error
}

func (h *%Model%Handler) Get%Model%(in *Get%Model%Input, out *Get%Model%Output) {
        ms := h.MS.Copy()
        defer ms.Close()
        c := ms.DB("").C("%Model%")
        out.Error = c.Find(bson.ObjectIdHex(in.AccountId)).All(&out.%Model%)
}

我需要添加或更改哪些内容,以便go generate从此假设的模板输出。如您所见,Address替换为%Model%

1 个答案:

答案 0 :(得分:9)

我不是go generate的专家,但是AFAIK,调用go来执行可构建go文件中指定的命令,通常是为了生成新的东西。

为搜索特定指令的文件生成扫描://go:generate,如果找到,它将执行后面的命令。

为了更好地理解正在发生的事情,让我们举一个简单的例子:模板go文件将有一个要替换的字符串。

示例1

让我们创建一个命令,将模板字符串NAME替换为另一个字符串AkiRoss

repl.sh

#!/usr/bin/sh
sed "s/NAME/AkiRoss/g" $1 > $2

以下是go模板,请注意指令:

templ.go

package main

import "fmt"

//go:generate ./repl.sh $GOFILE aki_$GOFILE

func main() {
    fmt.Println("Hello,", NAME)
}

为方便起见,两个文件都在同一目录中,repl.sh是可执行的。如果我在目录中运行go generate,则go工具会调用repl.sh templ.go aki_templ.go,将$GOFILE扩展为由generate处理的文件的名称。

这是我得到的:

aki_templ.go

package main

import "fmt"

//go:generate ./repl.sh $GOFILE aki_$GOFILE

func main() {
        fmt.Println("Hello,", AkiRoss)
}

示例2

关于您的示例,您需要将//go:generate指令放在某处。但是,该指令很可能包含在一个不同的文件中,而不是模板文件中,它调用替换脚本(类似于我制作的脚本)来生成构建所需的文件。

让我通过改变我的例子来解释这个:

repl.sh

#!/usr/bin/sh
sed "s/%NAME%/$3/g" $1 > $2

templ.txt

// This is a template for a go file
package main

import "fmt"

type %NAME% struct {
    foo string
    bar int
}

func (self *%NAME%) Perform() {
    fmt.Println(self.foo, self.bar)
}

main.go

package main

import "fmt"

//go:generate ./repl.sh templ.txt foobar.go FooBar

func main() {
    var fb = FooBar{"AkiRoss", -1}
    fmt.Println("Running!")
    fb.Perform()
}

运行go generate将生成新文件

foobar.go

// This is a template for a go file
package main

import "fmt"

type FooBar struct {
        foo string
        bar int
}

func (self *FooBar) Perform() {
        fmt.Println(self.foo, self.bar)
}

允许现在正确编译main:

$ go build
$ ./program
Running!
AkiRoss -1

我希望这澄清了。

参考

更多详情here,更好的例子是here