如何“动态地”评估外部 Go 源代码?

huangapple go评论92阅读模式
英文:

How to evaluate external go source code "dynamically"?

问题

我需要解析一个Go源代码文件,找到特定的类型(通过名称),并在我的程序中使用它。
我已经使用go/ast包找到了我需要的类型,但是我不知道如何将它"加载"到我的程序中以便我可以使用它。

问题:从外部源代码文件中提取和使用类型的最佳方法是什么?

除了一个丑陋的方法,我想不到其他办法,基本上是复制文件,通过注入一个带有我的编码内容的"main"函数来修改它,将结果发送到stdout,执行它,从stdout收集编码数据,然后删除修改后的文件。

用例:分析Go源代码并以特定格式(例如JSON模式)对类型进行编码。

编辑:
这里有一些代码。问题是如何对type allTypes(零值)进行编码,然后打印它。

package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"encoding/json"
)

var src string = `
package mypack

type allTypes struct{
	Brands Brands
	Colours Colours
}
type Brands struct{
	Sony string
	Apple string
}

type Colours struct{
	Red string
	Green string
}

`

type sometype struct{
	Nothing int
}

func main() {
	// src is the input for which we want to inspect the AST.

	// Create the AST by parsing src.
	fset := token.NewFileSet() // positions are relative to fset
	f, err := parser.ParseFile(fset, "src.go", src, 0)
	if err != nil {
		panic(err)
	}

	// Inspect the AST and find our function
	var tp ast.TypeSpec
	ast.Inspect(f, func(n ast.Node) bool {
		switch x := n.(type) {
		case *ast.TypeSpec:
			if x.Name.Name == "allTypes"{
				tp = *x
			}
		}
		return true
	})
	
	fmt.Printf("我们找到了类型:%v", tp)
	// Encode the zero value of sometype
	x := sometype{}
	b, _ := json.Marshal(&x)
	fmt.Printf("\n someType的零值(json)%s", b)
	//下一个问题:如何对"allTypes"的零值进行编码?
}

也可以在playground上查看。

英文:

I need to parse a Go source code file, find a specific type (by name) and use it in my program.
I already managed to find the type I need using the go/ast package but I don't know how to "load" it into my program so that I can use it.

Question: What's the best way to extract and use a type from an external source code file and use it on runtime?

I can't think of anything except an ugly method to basically copy the file, modify it by injecting a "main" function with my encoding stuff which sends the result to stdOut, execute the it, collect the encoded data from stdout, delete the modified file.

Use case: Analyse go source code and encode the types in a specific format (e.g. json schema)

Edit:
Here is some code. The question is how to encode type allTypes (zero value) and then print it.

package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"encoding/json"
)
	var src string = `
package mypack

type allTypes struct{
	Brands Brands
	Colours Colours
}
type Brands struct{
	Sony string
	Apple string
}

type Colours struct{
	Red string
	Green string
}
 
`
type sometype struct{
	Nothing int
}
func main() {
	// src is the input for which we want to inspect the AST.

	// Create the AST by parsing src.
	fset := token.NewFileSet() // positions are relative to fset
	f, err := parser.ParseFile(fset, "src.go", src, 0)
	if err != nil {
		panic(err)
	}

	// Inspect the AST and find our function
	var tp ast.TypeSpec
	ast.Inspect(f, func(n ast.Node) bool {
		switch x := n.(type) {
		case *ast.TypeSpec:
			if x.Name.Name == "allTypes"{
				tp = *x
			}
		}
		return true
	})
	
 	fmt.Printf("We found the type: it is %v", tp)
	// Encode the zero value of sometype
	x := sometype{}
	b, _ := json.Marshal(&x)
	fmt.Printf("\n Zero value of someType (json) %s", b)
	//Next/Question: How to encode the zero value of "allTypes" ???
}

Also on playground

答案1

得分: 1

如果我理解正确,你正在询问类似于Java的Class.forName(String className)的动态类型加载。简短的回答是Go语言不支持这个功能。

正确的方法,正如Nick Johnson指出的,是使用ast解析树,然后自己“生成”JSON。你将无法“加载”类型并使用JSON.Marshal。值得注意的是,任何支持json.Marshaler接口的类型都可以生成自定义的JSON。你还需要忽略但标记可选的“omitempty”行为。这实际上阻止你使用编译并通过“stdout”进行操作的行为。

英文:

If I understand you are asking for dynamic type loading ala Java's Class.forName(String className). The short answer is Go doesn't support this.

The correct way, as Nick Johnson pointed out, is to parse the tree using ast, and then "generate" the JSON yourself. You will not be able to "load" the type and use JSON.Marshal. It is also worth noting that any type which supports the json.Marshaler interface may generate custom JSON. You also need to ignore, but mark optional "omitempty" behavior. This really prevents you from using the compile it and hack through "stdout" behavior as well.

答案2

得分: 0

如果您需要在运行时提取类型信息,您需要使用reflect包。这是Go语言的encoding/json和其他类似包的工作方式。

英文:

If you need to extract type information at runtime, you need to use the reflect package. This is the way Go's encoding/json and other similar packages work.

答案3

得分: 0

如果你想操作在Go源文件中定义的类型,你可以使用go.parser包来读取和解析源文件为AST,然后遍历AST以查找你想要检查的元素。

英文:

If you want to operate on the types defined in a Go source file, you can use the go.parser package to read and parse a source file into an AST, then traverse the AST for the elements you want to examine.

答案4

得分: 0

似乎没有办法加载从源代码中提取的类型信息(如果我理解错了,请纠正我)。唯一的解决方案是创建/生成一个包(main),将从目标源代码文件中提取的所有类型注入其中,构建/编译它,执行它并从标准输出中收集编码数据。

英文:

It seems there is no way to load the type information extracted from the source code(please correct me if I'm wrong). The only solution is to create/generate a package (main), inject it with all the types extracted from the target source code file, build/compile it, execute it and collect the encoded data from stdout.

huangapple
  • 本文由 发表于 2015年1月31日 15:34:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/28249366.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定