сканирование абстрактного синтаксического дерева (AST)

# #go #casting #abstract-syntax-tree

Вопрос:

Я пытаюсь извлечь вызовы функций из go AST:

 $ cat main.go
package main
import ("fmt"; "go/ast"; "go/token"; "go/parser"; "io/ioutil")

func CalledFuncs(n ast.Node) bool {
    switch n.(type) {
    case *ast.CallExpr:
        l := ast.CallExpr(n).Lparen
        r := ast.CallExpr(n).Right
        fmt.Printf("call %d( ... %d)n",l,r)
    }
    return true
}

func main() {
    fset := token.NewFileSet()
    src,_ := ioutil.ReadFile("simple.go")
    f, _ := parser.ParseFile(fset,">>",src,0)
    ast.Inspect(f, CalledFuncs)
}
 

Но компилятор go жалуется, что я не могу выполнить кастинг:

 $ go build -o main main.go
# command-line-arguments
./main.go:7:26: cannot convert n (type ast.Node) to type ast.CallExpr
./main.go:8:26: cannot convert n (type ast.Node) to type ast.CallExpr
 

Я, наверное, что-то здесь упускаю.

Комментарии:

1. Компилятор прав, вы не можете преобразовать интерфейс в конкретный тип, даже если конкретный тип является динамическим типом переменной интерфейса. Возможно, вы захотите освежить в памяти golang.org/ref/spec#Conversions и golang.org/ref/spec#Type_switches . Вот что вам, вероятно, следует делать: play.golang.org/p/Ulj9I-P5da2

2. @OrenIshShalom: это очень простой ход. Любой хороший учебник должен охватывать это, когда он охватывает интерфейсы.

Ответ №1:

https://golang.org/ref/spec#Type_switches

Это TypeSwitchGuard может включать краткое объявление переменной. При использовании этой формы переменная объявляется TypeSwitchCase в конце неявного блока каждого предложения. В предложениях с регистром, в котором указан только один тип, переменная имеет этот тип; в противном случае переменная имеет тип выражения в TypeSwitchGuard .

Это означает, что вы можете сделать следующее:

 func CalledFuncs(n ast.Node) bool {
    switch x := n.(type) {
    case *ast.CallExpr:
        l := x.Lparen
        r := x.Rparen
        fmt.Printf("call %d( ... %d)n", l, r)
    }
    return true
}