查找使用 x/tools/go/packages 嵌入另一种类型的类型

假设我有下面的代码,


package w


import "log"


type Z struct {

    log.Logger

}


type Y struct {} // skip this type


我想以编程方式查找类型,由它嵌入的事实标识,如果它没有,我想跳过声明,使用 https://pkg.go.dev/golang.org/x/tools/go/packagesZlog.Logger


目前我已经能够编写以下代码,


package main


import (

    "fmt"

    "go/ast"

    "go/token"

    "os"

    "path/filepath"


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

)


func main() {

    inputFile := os.Getenv("GOFILE")

    cwd, err := os.Getwd()

    if err != nil {

        panic(err)

    }

    fmt.Println(inputFile)

    fmt.Println(cwd)


    cfg := &packages.Config{

        // Mode:       packages.NeedName | packages.NeedFiles | packages.NeedSyntax | packages.LoadTypes,

        Mode:       packages.NeedSyntax | packages.LoadTypes,

        BuildFlags: []string{"-tags=sqlg"},

    }

    pkgs, err := packages.Load(cfg, cwd)

    if err != nil {

        fmt.Fprintf(os.Stderr, "load: %v\n", err)

        os.Exit(1)

    }

    if packages.PrintErrors(pkgs) > 0 {

        os.Exit(1)

    }


    for _, pkg := range pkgs {

        fmt.Println(pkg.ID, pkg.GoFiles)

        for _, s := range pkg.Syntax {

            file := pkg.Fset.File(s.Pos())

            if filepath.Base(file.Name()) != inputFile {

                continue

            }

            for _, d := range s.Decls {

                switch x := d.(type) {

                case *ast.GenDecl:

                    if x.Tok == token.TYPE {

                        fmt.Printf("%#v\n", x.Specs)

                    }

                case *ast.FuncDecl:

                }

            }

        }

    }

}

但我不太喜欢它,因为我正在挖掘语法树,寻找GenDecl,然后是Specs等


以前,使用包加载器可以加载类型推断,搜索每个包的类型并检查接口兼容性;它对我来说很满意,我想要类似的东西。https://godoc.org/golang.org/x/tools/go/loader


如何使用新的包包来查找类型,因为它们嵌入了简单的特定类型?


梵蒂冈之花
浏览 147回答 2
2回答

慕勒3428872

有一个在go/types包。Var.Embedded可以使用 use 加载包并获取类型信息,然后使用 和 接口强制转换为筛选出结构类型,然后使用迭代来获取字段,并选中 .golang.org/x/tools/go/loaderType.UnderlyingStruct.FiledVarVar

智慧大石

多亏了叶子bebop的答案,我能够写一个更短的程序,原始帖子没有显示,但在v1中,我有8个级别的缩进来查找结构的嵌入属性。这受到&nbsp;https://pkg.go.dev/golang.org/x/tools@v0.0.0-20201226215659-b1c90890d22a/go/packages/gopackages&nbsp;提供的演示的启发package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "go/types"&nbsp; &nbsp; "os"&nbsp; &nbsp; "strings"&nbsp; &nbsp; "golang.org/x/tools/go/packages")func main() {&nbsp; &nbsp; inputFile := os.Getenv("GOFILE")&nbsp; &nbsp; cwd, err := os.Getwd()&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(inputFile)&nbsp; &nbsp; fmt.Println(cwd)&nbsp; &nbsp; cfg := &packages.Config{&nbsp; &nbsp; &nbsp; &nbsp; // Mode:&nbsp; &nbsp; &nbsp; &nbsp;packages.NeedName | packages.NeedFiles | packages.NeedSyntax | packages.LoadTypes,&nbsp; &nbsp; &nbsp; &nbsp; Mode:&nbsp; &nbsp; &nbsp; &nbsp;packages.NeedSyntax | packages.LoadTypes,&nbsp; &nbsp; }&nbsp; &nbsp; pkgs, err := packages.Load(cfg, cwd)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Fprintf(os.Stderr, "load: %v\n", err)&nbsp; &nbsp; &nbsp; &nbsp; os.Exit(1)&nbsp; &nbsp; }&nbsp; &nbsp; if packages.PrintErrors(pkgs) > 0 {&nbsp; &nbsp; &nbsp; &nbsp; os.Exit(1)&nbsp; &nbsp; }&nbsp; &nbsp; for _, pkg := range pkgs {&nbsp; &nbsp; &nbsp; &nbsp; // qual := types.RelativeTo(pkg.Types)&nbsp; &nbsp; &nbsp; &nbsp; scope := pkg.Types.Scope()&nbsp; &nbsp; &nbsp; &nbsp; for _, name := range scope.Names() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; obj := scope.Lookup(name)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if obj != nil && obj.Type() != nil && obj.Type().Underlying() != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // obj is types.Named,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // obj.Type() is types.TypeName&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // obj.Type().Underlying() exposes the types.Struct which&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // gives access to the desired types.Var.Embedded()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; st, ok := obj.Type().Underlying().(*types.Struct)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if !ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < st.NumFields(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f := st.Field(i)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if f.Embedded() && strings.HasSuffix(f.Type().String(), "log.Logger") {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("%#v\n", f)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}我相信它存在一个使用访问者模式的较短版本,但我还没有找到它。在这个版本中,我仍然依靠字符串比较来类型检查属性,这是以后使用类型推断可以改进的东西。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go