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

Posted

技术标签:

【中文标题】从读取 .go 文件中反思结构类型【英文标题】:Reflect on struct type from reading a .go file 【发布时间】:2019-05-15 21:57:43 【问题描述】:

我正在发现生成器 (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 以直接访问类型的文件

【问题讨论】:

您看过go/parsergo/astgo/token 软件包了吗?您可以阅读该文件,并对代码进行标记,并使用它来生成代码。有很多这样的包的例子。例如,Google 自己的 mockgen 会浮现在脑海中 我推荐ast 包golang.org/pkg/go/ast 我不知道这些包,看起来正是我要找的,谢谢 反射的定义是用于运行时,而不是用于解析源代码。 更喜欢使用 go/loader 和 go/types 来 go/ast。 go/ast 是低级。 【参考方案1】:

不需要指定文件名,这段代码也是这样:

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

在文本/模板包的帮助下,您无需解析文件。一个非常简单的例子是这样的。这将为您提供线索:

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 很好,使用模板并不能解决我的问题,它有助于生成输出代码,但我仍然需要从原始文件中获取对象

以上是关于从读取 .go 文件中反思结构类型的主要内容,如果未能解决你的问题,请参考以下文章

Go 语言的设计反思

一次 Go 程序 out of memory 排查及反思

golang Go的反思例子

上个项目的一些反思 III

工作记录+反思

反思 - Java 8 - 无效的常量类型