英文:
Parsing go src, trying to convert *ast.GenDecl to types.Interface
问题
我正在尝试解析包含接口的Go源文件,并找到接口定义的方法/签名。我正在使用ast来解析文件。我能够获取一些高级声明,比如*ast.GenDecl,但是我无法进一步确定这个类型是否是接口以及它的方法是什么。
这是我正在解决的一个脚手架类型的问题,用户定义了一个服务的接口,然后工具将构建出服务的框架。
package main
import (
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
    "reflect"
)
func main() {
    fset := token.NewFileSet()
    f, _ := parser.ParseFile(fset, "/tmp/tmp.go", `package service
    type ServiceInterface interface {
        Create(NewServiceRequest) (JsonResponse, error)
        Delete(DelServiceRequest) (JsonResponse, error)
    }`, 0)
    for _, v := range f.Decls {
        switch t := v.(type) {
        case *ast.FuncDecl:
            fmt.Println("func ", t.Name.Name)
        case *ast.GenDecl:
            switch x := t.Specs[0].(type) {
            default:
                fmt.Println(x, reflect.TypeOf(x))
            }
        default:
            fmt.Printf("skipping %t\n", t)
        }
    }
}
但是我似乎无法找到关于接口声明内部的任何信息。
&{<nil> ServiceInterface 0x8202d8260 <nil>} *ast.TypeSpec
英文:
I am trying to parse go source files that contain interfaces and find the interfaces defined methods / signatures. I am using ast to parse the file. I am able to get some high level declarations, such as *ast.GenDecl, but I am not able to get to the next level of determining if this type is an interface and what its methods are.
This is for a scaffolding type problem I am trying to solve where a user defines the interface for a service and a tool will build out the skeleton of the service
package main
import (
        "fmt"
        "go/ast"
        "go/parser"
        "go/token"
        "reflect"
)
func main() {
        fset := token.NewFileSet()
        f, _ := parser.ParseFile(fset, "/tmp/tmp.go", `package service
        type ServiceInterface interface {
                        Create(NewServiceRequest) (JsonResponse, error)
                        Delete(DelServiceRequest) (JsonResponse, error)
        }`, 0)
        for _, v := range f.Decls {
            switch t := v.(type) {
            case *ast.FuncDecl:
                    fmt.Println("func ", t.Name.Name)
            case *ast.GenDecl:
                    switch x := t.Specs[0].(type) {
                    default:
                            fmt.Println(x, reflect.TypeOf(x))
                    }
            default:
                    fmt.Printf("skipping %t\n", t)
            }
    }
}
Results in but I cant seem to find anything about the internals of interface declaration at all.
&{<nil> ServiceInterface 0x8202d8260 <nil>} *ast.TypeSpec
答案1
得分: 7
使用AST进行工作时,我发现使用spew包来转储示例非常有帮助:
fset := token.NewFileSet()
f, _ := parser.ParseFile(fset, "/tmp/tmp.go", `package service ....`)
spew.Dump(f)
我发现从spew输出中编写所需的代码很容易。
以下是一些代码,可以帮助你入门。它打印接口和方法名称:
package main
import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
)
func main() {
	fset := token.NewFileSet()
	f, _ := parser.ParseFile(fset, "/tmp/tmp.go", `package service
type ServiceInterface interface {
	Create(NewServiceRequest) (JsonResponse, error)
	Delete(DelServiceRequest) (JsonResponse, error)
}`, 0)
	for _, x := range f.Decls {
		if x, ok := x.(*ast.GenDecl); ok {
			if x.Tok != token.TYPE {
				continue
			}
			for _, x := range x.Specs {
				if x, ok := x.(*ast.TypeSpec); ok {
					iname := x.Name
					if x, ok := x.Type.(*ast.InterfaceType); ok {
						for _, x := range x.Methods.List {
							if len(x.Names) == 0 {
								continue
							}
							mname := x.Names[0].Name
							fmt.Println("interface:", iname, "method:", mname)
						}
					}
				}
			}
		}
	}
}
你可以在这里查看运行结果:http://play.golang.org/p/eNyB7O6FIc
英文:
When working with the AST, I find it helpful to dump an example using the spew package:
    fset := token.NewFileSet()
    f, _ := parser.ParseFile(fset, "/tmp/tmp.go", `package service ....`)
    spew.Dump(f)
I find it easy to write the required code from the spew output.
Here's some code to get you started. It prints interface and method names:
package main
import (
  "fmt"
  "go/ast"
  "go/parser"
  "go/token"
)
func main() {
  fset := token.NewFileSet()
  f, _ := parser.ParseFile(fset, "/tmp/tmp.go", `package service
    type ServiceInterface interface {
                    Create(NewServiceRequest) (JsonResponse, error)
                    Delete(DelServiceRequest) (JsonResponse, error)
    }`, 0)
  for _, x := range f.Decls {
	if x, ok := x.(*ast.GenDecl); ok {
		if x.Tok != token.TYPE {
			continue
		}
		for _, x := range x.Specs {
			if x, ok := x.(*ast.TypeSpec); ok {
				iname := x.Name
				if x, ok := x.Type.(*ast.InterfaceType); ok {
					for _, x := range x.Methods.List {
						if len(x.Names) == 0 {
							continue
						}
						mname := x.Names[0].Name
						fmt.Println("interface:", iname, "method:", mname)
					}
				}
			}
		}
	}
  }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论