从读取.go文件中反映出结构类型

4
我正在了解生成器(go generate)并尝试为我的结构体生成验证函数。
我的想法是,我不希望程序在运行时使用反射,而是希望生成器使用反射来生成我想要使用的实际方法。
问题在于我无法在生成器代码中导入我的结构体,目前我找到的唯一方法是从生成器中读取.go文件,并使用正则表达式手动解析其中定义的类型。
我已经得到了类似这样的东西:
models/models.go:
package models

//go:generate go run ../generator.go -file models.go

type MyStruct struct {
    ...
}

generator.go:

package main

func main() {
    f, err := ioutil.ReadFile(fileName) // I read filename from the flag provided
    ...
    // I parse f to generate my stuff
}

我希望有一个内省包,可以将Go代码作为字符串输入,并提供关于其中定义的结构的一些信息。
或者也许有一种方法可以导入调用go:generate的文件,以直接访问类型。

8
你是否查看过go/parsergo/astgo/token包?你可以读取文件,对代码进行分词,并用它生成代码。这方面有很多包的示例可供参考。例如,谷歌自己的mockgen - Elias Van Ootegem
1
我建议使用ast包 https://golang.org/pkg/go/ast/ - ssemilla
我之前不知道这些包,看起来正是我需要的,谢谢。 - BlueMagma
1
反射的定义是用于运行时,而不是解析源代码。 - Adrian
更倾向于使用go/loader和go/types而不是go/ast。go/ast属于低级别。 - user4466350
2个回答

1

1

不需要指定文件名,这段代码也可以实现相同的功能:

//go:generate go run ../generator.go -file $GOFILE

通过使用text/template包,您无需解析文件。一个非常简单的示例可能是这样的。这会给您提示:

package main

import (
    "flag"
    "os"
    "text/template"
)

//go:generate go run main.go -name=A
//go:generate go run main.go -name=B
//go:generate go run main.go -name=C

var name = flag.String("name", "test", "name of struct")

var code = `
package main

type Struct{{.}} struct {}

func (s *Struct{{.}} ) Vailadte() bool {
return true
}
`

func main() {
    flag.Parse()
    file, _ := os.Create(*name + ".go")
    defer file.Close()

    tmpl, _ := template.New("test").Parse(code)
    tmpl.Execute(file, *name)
}

谢谢,使用$GOFILE很好,但是使用模板并不能解决我的问题,虽然它可以帮助生成输出代码,但我仍然需要从原始文件中获取对象。 - BlueMagma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接