确定动态指定的Go变量是否具有特定类型
我正在编写一个命令行应用程序,其中用户指定1)一个包含Go文件的目录,2)一个变量的名称,该变量应该是确定动态指定的Go变量是否具有特定类型,go,Go,我正在编写一个命令行应用程序,其中用户指定1)一个包含Go文件的目录,2)一个变量的名称,该变量应该是http.Handler,例如 go run cli.go /path/to/a/go/library MyCustomHandler 我正在努力 解析文件 查找具有给定名称的变量 验证它是一个http.Handler 我可以毫无问题地完成前两个任务-我调用parser.ParseDir,然后将我想要的包作为*ast.package,然后像这样循环: func findHttpHandle
http.Handler
,例如
go run cli.go /path/to/a/go/library MyCustomHandler
我正在努力
- 解析文件
- 查找具有给定名称的变量
- 验证它是一个
http.Handler
parser.ParseDir
,然后将我想要的包作为*ast.package
,然后像这样循环:
func findHttpHandler(pkg *ast.Package, handlerName string) (*ast.FuncDecl, error) {
for _, file := range pkg.Files {
for _, decl := range file.Decls {
gd, ok := decl.(*ast.GenDecl)
if !ok || gd.Tok != token.VAR {
continue
}
if len(gd.Specs) != 1 {
continue
}
spec0 := gd.Specs[0]
vs, ok := spec0.(*ast.ValueSpec)
if !ok {
continue
}
if len(vs.Names) != 1 {
continue
}
ident := vs.Names[0]
if ident.Name != handlerName {
continue
}
// ...
}
}
}
问题是此时ValueSpec.Type
为nil,并且似乎没有任何方法可以确定这是否是http.Handler
go/types
软件包有更多的检查类型的工具,但是看起来你还需要做更多的设置工作才能做到这一点,基本上就是对整个程序进行解析和类型检查。我是否需要沿着这条路走下去,或者是否有更简单的方法,只是使用ast
包,或者以某种方式使用go build
?做了一些跟踪并找到了方法,希望得到帮助
嗨,凯文!:)这看起来很接近这个问题:我希望它有帮助。
package main
import (
"go/parser"
"go/token"
"os"
"go/ast"
"log"
"net/http"
//"reflect"
)
func MyCustomHandler(w http.ResponseWriter, r* http.Request){
}
func findHttpHandler(pkg *ast.Package, handlerName string) (*ast.FuncDecl, error) {
for _, file := range pkg.Files {
for _, decl := range file.Decls {
fd, ok := decl.(*ast.FuncDecl)
if !ok || fd == nil{
continue
}
if fd.Name.Name != handlerName{
continue
}
if len(fd.Type.Params.List) == 2 {
p1 := fd.Type.Params.List[0]
p2 := fd.Type.Params.List[1]
exp, ok := p1.Type.(*ast.SelectorExpr)
if !ok{
break;
}
ident, ok := exp.X.(*ast.Ident)
if !ok{
break
}
if ident.Name!="http" || exp.Sel.Name != "ResponseWriter"{
break;
}
exp2, ok := p2.Type.(*ast.StarExpr)
if !ok{
break;
}
exp = exp2.X.(*ast.SelectorExpr)
ident, ok = exp.X.(*ast.Ident)
if !ok{
break
}
if ident.Name!="http" || exp.Sel.Name != "Request"{
break;
}
return fd, nil
}
}
}
return nil, nil
}
func main() {
fs := token.NewFileSet()
pkgs, err := parser.ParseDir(fs, os.Args[1], nil, parser.Trace)
if err != nil{
log.Fatalln(err)
}
for _,pkg:=range pkgs{
d, _ := findHttpHandler(pkg, "MyCustomHandler");
log.Println(d)
}
}