0

I have read through the piece of code bellow and I don't know what exactly the syntax of d.() in if f, ok := d.(*ast.FuncDecl); mean.

Can anybody explain it for me?

package main

import (
    "go/ast"
    "go/parser"
    "go/token"
    "regexp"

    "github.com/posener/complete"
)

func functionsInFile(path string, regexp *regexp.Regexp) (tests []string) {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, path, nil, 0)
    if err != nil {
        complete.Log("Failed parsing %s: %s", path, err)
        return nil
    }
    for _, d := range f.Decls {
        if f, ok := d.(*ast.FuncDecl); ok {
            name := f.Name.String()
            if regexp == nil || regexp.MatchString(name) {
                tests = append(tests, name)
            }
        }
    }
    return
}
Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412
Minh Tri Le
  • 350
  • 2
  • 12

1 Answers1

2

As the comments say, this is a type assertion. Type assertions are described in the Go spec: https://golang.org/ref/spec#Type_assertions

Applied to your specific code sample, I think it's taken from the AST module documentation, which you should read if you want to work with Go ASTs.

ParseFile returns an ast.File, which is:

type File struct {
        Doc        *CommentGroup   // associated documentation; or nil
        Package    token.Pos       // position of "package" keyword
        Name       *Ident          // package name
        Decls      []Decl          // top-level declarations; or nil
        Scope      *Scope          // package scope (this file only)
        Imports    []*ImportSpec   // imports in this file
        Unresolved []*Ident        // unresolved identifiers in this file
        Comments   []*CommentGroup // list of all comments in the source file
}

So Decls is a slice of Decl, which is an interface. In brief, this means that at compile-time you don't know what the actual underlying type is (though you do know it satisfies the interface), so you do a run-time type assertion to verify it's something you expect.

    if f, ok := d.(*ast.FuncDecl); ok {
        name := f.Name.String()
        if regexp == nil || regexp.MatchString(name) {
            tests = append(tests, name)
        }
    }

This means "if d is actually a FuncDecl, do this thing".

Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412