为了账号安全,请及时绑定邮箱和手机立即绑定

如何以编程方式检索声明给定类型的包路径?

如何以编程方式检索声明给定类型的包路径?

Go
慕盖茨4494581 2022-04-26 14:27:52
我正在寻找一种方法来检索本地安装的包,其中包含给定类型的声明和默认包名称。IE:// FindPackagesForType returns the list of possible packages for a given typefunc FindPackagesForType(typeName string) []string {    return []string {} // TODO: implement}func TestFindPackagesForType(t *testing.T) {    assert.Contains(t, FindPackagesForType("io.Reader"), "io")    assert.Contains(        t,        FindPackagesForType("types.Timestamp"),        "github.com/gogo/protobuf/types",    )    assert.Contains(        t,        FindPackagesForType("types.ContainerCreateConfig"),        "github.com/docker/docker/api/types",    )}我可以尝试检索所有已安装的包,并在每个查找声明时通过 AST,但如果有一个解决方案可以更有效地做到这一点,同时还提供对 go 模块的支持,我想使用它。这样做的原因是为了改进代码生成工具。这个想法是让用户提供类型的名称,并让工具识别最有可能的候选者,就像 goimports 添加缺失的导入一样。
查看完整描述

2 回答

?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

您可以使用reflect.TypeOf(any).PkgPath()获取特定类型的包路径。但是,我们需要传递具有所需类型的对象(而不是您想要的字符串)。


package main


import (

    "bytes"

    "fmt"

    "reflect"

    "gopkg.in/mgo.v2/bson"

)


func main() {

    var a bytes.Buffer

    fmt.Println(FindPackagesForType(a)) // output: bytes


    var b bson.M

    fmt.Println(FindPackagesForType(b)) // output: gopkg.in/mgo.v2/bson

}


func FindPackagesForType(any interface{}) string {

    return reflect.TypeOf(any).PkgPath()

}


查看完整回答
反对 回复 2022-04-26
?
慕的地10843

TA贡献1785条经验 获得超8个赞

下面的程序列表uses和definitions给定的查询type和给定的 go 包。


使用程序加载器包以编程方式加载 go 程序简单明了


package main


import (

    "flag"

    "fmt"

    "strings"


    "golang.org/x/tools/go/loader"

)


func main() {


    var query string

    var uses bool

    var defs bool

    flag.StringVar(&query, "query", "", "the fully qualified type path")

    flag.BoolVar(&uses, "uses", true, "capture uses")

    flag.BoolVar(&defs, "definitions", true, "capture definitions")

    flag.Parse()


    if query == "" {

        panic("query must not be empty")

    }


    var queryPkg string

    queryType := query

    if i := strings.LastIndex(query, "."); i > -1 {

        queryPkg = query[:i]

        queryType = query[i+1:]

    }


    var conf loader.Config

    _, err := conf.FromArgs(flag.Args(), false)

    if err != nil {

        panic(err)

    }

    prog, err := conf.Load()

    if err != nil {

        panic(err)

    }


    for pkgType, pkgInfo := range prog.AllPackages {

        if queryPkg != "" {

            if !strings.HasPrefix(pkgType.Path(), queryPkg) {

                continue

            }

        }

        if defs {

            for typeInfo, ident := range pkgInfo.Defs {

                if !strings.HasPrefix(typeInfo.Name, queryType) {

                    continue

                }

                f := prog.Fset.File(ident.Pos())

                fpos := f.Position(ident.Pos())

                fmt.Printf("def: %v %v.%v\n", fpos, pkgType.Path(), typeInfo.Name)

            }

        }


        if uses {

            for ident, oInfo := range pkgInfo.Uses {

                if !strings.Contains(oInfo.Type().String(), queryType) {

                    continue

                }

                f := prog.Fset.File(ident.Pos())

                fpos := f.Position(ident.Pos())

                fmt.Printf("use: %v %v\n", fpos, oInfo.Type().String())

            }

        }

        // -

    }

}

然后你像这样运行它


$ go run main.go -query="io.Reader" io

def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:170:6 io.ReaderFrom

def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:77:6 io.Reader

def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:211:6 io.ReaderAt

use: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/multi.go:20:13 []io.Reader

use: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/multi.go:21:16 *io.multiReader

# a ton of output...

[mh-cbon@Host-001 ploader] $ go run main.go -query="Config" io

[mh-cbon@Host-001 ploader] $ go run main.go -query="io.Reader" -uses=false io

def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:170:6 io.ReaderFrom

def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:211:6 io.ReaderAt

def: /home/mh-cbon/.gvm/gos/go1.12.7/src/io/io.go:77:6 io.Reader

您可能需要改进匹配器引擎以使其更适合。


查看完整回答
反对 回复 2022-04-26
  • 2 回答
  • 0 关注
  • 102 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信