我有文件夹,其中.go
定义了文件和函数。
是否可以在命令行中列出当前文件夹中的所有函数声明,可能是godoc
?
godoc list functions /path/to/fileOrFolder
要有这样的输出:
func Foo(a, b int) int
func Bar(c, d int) int
绝对彼得的答案是非常充分的,但如果你想进入兔子洞......并且为了它的乐趣。使用 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
}
基于@Peter 的方法理念,您可以使用简单的 grep + regex 提取所有导出的函数,如下所示:
grep -rP '^func\s(?:\([^\)]+\)\s)?[A-Z].*' *.go