【问题标题】:List all functions from source code列出源代码中的所有函数
【发布时间】:2018-09-09 10:11:36
【问题描述】:

我有一个文件夹,里面定义了.go 文件和函数。

是否可以在命令行中列出当前文件夹中的所有函数声明,可能是godoc

godoc list functions /path/to/fileOrFolder

要有这样的输出:

func Foo(a, b int) int
func Bar(c, d int) int

【问题讨论】:

  • 忽略匿名函数:grep ^func *.go
  • 我在我的 Mac 上使用这个 grep -re '^func' ~/projects/myproject

标签: go godoc


【解决方案1】:

Peter 的回答肯定是非常充分的,但如果你想从兔子洞里钻进去……而且为了它的乐趣。使用 golang std lib ast 的强大功能。

package main

import (
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
    "io/ioutil"
    "log"
    "os"
)

func main() {
    // read file
    // here you can filepath.Walk() for your go files
    gopath := os.ExpandEnv("$GOPATH")
    fname := gopath + "/src/github.com/golang/protobuf/proto/lib.go"

    // read file
    file, err := os.Open(fname)
    if err != nil {
        log.Println(err)
        return
    }
    defer file.Close()

    // read the whole file in
    srcbuf, err := ioutil.ReadAll(file)
    if err != nil {
        log.Println(err)
        return
    }
    src := string(srcbuf)

    // file set
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "lib.go", src, 0)
    if err != nil {
        log.Println(err)
        return
    }

    // main inspection
    ast.Inspect(f, func(n ast.Node) bool {

        switch fn := n.(type) {

        // catching all function declarations
        // other intersting things to catch FuncLit and FuncType
        case *ast.FuncDecl:
            fmt.Print("func ")

            // if a method, explore and print receiver
            if fn.Recv != nil {
                fmt.Printf("(%s)", fields(*fn.Recv))
            }

            // print actual function name
            fmt.Printf("%v", fn.Name)

            // print function parameters
            if fn.Type.Params != nil {
                fmt.Printf("(%s)", fields(*fn.Type.Params))
            }

            // print return params
            if fn.Type.Results != nil {
                fmt.Printf("(%s)", fields(*fn.Type.Results))
            }

            fmt.Println()

        }
        return true
    })
}

func expr(e ast.Expr) (ret string) {
    switch x := e.(type) {
    case *ast.StarExpr:
        return fmt.Sprintf("%s*%v", ret, x.X)
    case *ast.Ident:
        return fmt.Sprintf("%s%v", ret, x.Name)
    case *ast.ArrayType:
        if x.Len != nil {
            log.Println("OH OH looks like homework")
            return "TODO: HOMEWORK"
        }
        res := expr(x.Elt)
        return fmt.Sprintf("%s[]%v", ret, res)
    case *ast.MapType:
        return fmt.Sprintf("map[%s]%s", expr(x.Key), expr(x.Value))
    case *ast.SelectorExpr:
        return fmt.Sprintf("%s.%s", expr(x.X), expr(x.Sel))
    default:
        fmt.Printf("\nTODO HOMEWORK: %#v\n", x)
    }
    return
}

func fields(fl ast.FieldList) (ret string) {
    pcomma := ""
    for i, f := range fl.List {
        // get all the names if present
        var names string
        ncomma := ""
        for j, n := range f.Names {
            if j > 0 {
                ncomma = ", "
            }
            names = fmt.Sprintf("%s%s%s ", names, ncomma, n)
        }
        if i > 0 {
            pcomma = ", "
        }
        ret = fmt.Sprintf("%s%s%s%s", ret, pcomma, names, expr(f.Type))
    }
    return ret
}

【讨论】:

    【解决方案2】:

    基于@Peter 的方法理念,您使用简单的 grep + regex 提取所有导出的函数,如下所示:

    grep -rP '^func\s(?:\([^\)]+\)\s)?[A-Z].*' *.go
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-17
      • 2013-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多