Explain go generate in this example

与世无争的帅哥 提交于 2021-02-19 02:45:06

问题


I'm having difficulties understanding go generate. I also find barely any posts dealing with go generate.

please explain go generate in this following example:

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)
}

I would like to create almost carbon copies of this not yet template code.

the "template" code:

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%)
}

What do I need to add or change so I can go generate output from this supposed template. As you can see everything Address is replaced with %Model%.


回答1:


I am not expert with go generate, but AFAIK, go generate is called to perform commands specified in buildable go files, normally with the intent to produce something new.

Generate scans for files searching for a specific directive: //go:generate and, if found, it will execute the command following it.

To understand better what's happening, let's make a simple example: a template go file will have a string to be replaced.

Example 1

Let's make a command that replace the template string, NAME, with another string, AkiRoss:

repl.sh

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

Here follows the go template, note the directive:

templ.go

package main

import "fmt"

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

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

Both files are in the same directory, for convenience, and repl.sh is executable. If I run go generate in the directory, the go tool will call repl.sh templ.go aki_templ.go, being $GOFILE expanded to be the name of the file processed by generate.

Here's what I get:

aki_templ.go

package main

import "fmt"

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

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

Example 2

Regarding your example, you will need to place the //go:generate directive somewhere. It is likely, however, that the directive will be included in a different file, not the template file, that calls a replacement script, similar to the one I made, to produce a file which is needed for building.

Let me explain this better by changing my example:

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()
}

Running go generate will produce a new file

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)
}

which allows now to compile correctly the main:

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

I hope this clarified.

References

More details here, and a better example is here.



来源:https://stackoverflow.com/questions/37362054/explain-go-generate-in-this-example

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!