首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >确定动态指定的Go变量是否具有特定类型

确定动态指定的Go变量是否具有特定类型
EN

Stack Overflow用户
提问于 2016-05-17 15:06:30
回答 1查看 239关注 0票数 1

我正在编写一个命令行应用程序,其中用户指定1)包含Go文件的目录,2)应该是http.Handler的变量的名称。

代码语言:javascript
复制
go run cli.go /path/to/a/go/library MyCustomHandler

我在试着

  • 解析文件
  • 查找具有给定名称的变量
  • 验证它是一个http.Handler

我可以做前两个没有问题-我调用parser.ParseDir,然后得到我想要的包作为一个*ast.Package,然后循环它如下:

代码语言:javascript
复制
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为零,而且似乎没有任何方法来确定这是否是http.Handler

go/types包有更多用于检查类型的工具,但它似乎还需要做更多的设置工作才能实现这一点,本质上是解析和检查整个程序。我是否需要沿着这条路走下去,还是有更简单的方法,只使用ast包,还是以某种方式使用go build

EN

回答 1

Stack Overflow用户

发布于 2016-05-18 03:17:39

做了些追踪,找到了路,希望能帮上忙

FbL

代码语言:javascript
复制
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)
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37279890

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档