解析Go源代码,尝试将*ast.GenDecl转换为types.Interface。

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

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 (
        &quot;fmt&quot;
        &quot;go/ast&quot;
        &quot;go/parser&quot;
        &quot;go/token&quot;
        &quot;reflect&quot;
)

func main() {
        fset := token.NewFileSet()
        f, _ := parser.ParseFile(fset, &quot;/tmp/tmp.go&quot;, `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(&quot;func &quot;, t.Name.Name)
            case *ast.GenDecl:
                    switch x := t.Specs[0].(type) {
                    default:
                            fmt.Println(x, reflect.TypeOf(x))
                    }
            default:
                    fmt.Printf(&quot;skipping %t\n&quot;, t)
            }

    }
}

Results in but I cant seem to find anything about the internals of interface declaration at all.

&amp;{&lt;nil&gt; ServiceInterface 0x8202d8260 &lt;nil&gt;} *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, &quot;/tmp/tmp.go&quot;, `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 (
  &quot;fmt&quot;
  &quot;go/ast&quot;
  &quot;go/parser&quot;
  &quot;go/token&quot;
)

func main() {
  fset := token.NewFileSet()
  f, _ := parser.ParseFile(fset, &quot;/tmp/tmp.go&quot;, `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(&quot;interface:&quot;, iname, &quot;method:&quot;, mname)

					}
				}
			}
		}
	}
  }
}

http://play.golang.org/p/eNyB7O6FIc

huangapple
  • 本文由 发表于 2015年11月21日 05:27:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/33836358.html
匿名

发表评论

匿名网友

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

确定