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

时间:2015-01-31 07:34:10

标签: go static-analysis

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

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

除了一个丑陋的方法基本上复制文件,通过注入一个" main"来修改它,我什么也想不出来。函数与我的编码东西,将结果发送到stdOut,执行它,从stdout收集编码数据,删除修改后的文件。

用例:分析go源代码并以特定格式(例如json schema)编码类型

编辑: 这是一些代码。问题是如何编码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("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" ???
}

同样在playground

4 个答案:

答案 0 :(得分:1)

如果我理解你要求动态类型加载Java Class.forName(String className)。简短的回答是Go并不支持这一点。

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

如果要对Go源文件中定义的类型进行操作,可以使用go.parser包将源文件读取并解析为AST,然后遍历AST以查找要检查的元素

答案 3 :(得分:0)

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