Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go lang func parameter type

I am trying to find func parameter type and its name to generate some code. I am using ast package for it. I've found parameter name, but I can't find parameter type name.

for _, fun := range findFunc(node) { //ast.FuncDecl

    if  fun.Recv != nil {
        for _, field := range fun.Type.Params.List {
            for _, name := range field.Names {
                println(name.Name)  //Func field name
                //How to find field type name here?
            }

        }
    }

}
like image 701
Pavel Avatar asked May 25 '18 08:05

Pavel


1 Answers

You're on the right track, FuncType.Params is the (incoming) parameter list of the function. Its List field holds all the parameters, which are of type ast.Field:

type Field struct {
        Doc     *CommentGroup // associated documentation; or nil
        Names   []*Ident      // field/method/parameter names; or nil if anonymous field
        Type    Expr          // field/method/parameter type
        Tag     *BasicLit     // field tag; or nil
        Comment *CommentGroup // line comments; or nil
}

The Field.Type holds the type of the parameter which is an interface type ast.Expr with simply embeds the ast.Node which only provides you the start and end position of the type in the source. Basically this should be enough to get the text representation of the type.

Let's see a simple example. We will analyze this function:

func myfunc(i int, s string, err error, pt image.Point, x []float64) {}

And the code to print its parameters, including type names:

src := `package xx
func myfunc(i int, s string, err error, pt image.Point, x []float64) {}`

fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "src.go", src, 0)
if err != nil {
    panic(err)
}
offset := f.Pos()

ast.Inspect(f, func(n ast.Node) bool {
    if fd, ok := n.(*ast.FuncDecl); ok {
        fmt.Printf("Function: %s, parameters:\n", fd.Name)
        for _, param := range fd.Type.Params.List {
            fmt.Printf("  Name: %s\n", param.Names[0])
            fmt.Printf("    ast type          : %T\n", param.Type)
            fmt.Printf("    type desc         : %+v\n", param.Type)
            fmt.Printf("    type name from src: %s\n",
                src[param.Type.Pos()-offset:param.Type.End()-offset])
        }
    }
    return true
})

Output (try it on the Go Playground):

Function: myfunc, parameters:
  Name: i
    ast type          : *ast.Ident
    type desc         : int
    type name from src: int
  Name: s
    ast type          : *ast.Ident
    type desc         : string
    type name from src: string
  Name: err
    ast type          : *ast.Ident
    type desc         : error
    type name from src: error
  Name: pt
    ast type          : *ast.SelectorExpr
    type desc         : &{X:image Sel:Point}
    type name from src: image.Point
  Name: x
    ast type          : *ast.ArrayType
    type desc         : &{Lbrack:71 Len:<nil> Elt:float64}
    type name from src: []float64
like image 103
icza Avatar answered Nov 15 '22 07:11

icza