在Golang中进行多个接口转换的简明方法?
我试图使用在Golang中进行多个接口转换的简明方法?,go,abstract-syntax-tree,Go,Abstract Syntax Tree,我试图使用go/ast包解析代码中的函数调用 为此,我首先查找所有函数调用,如: ast.Inspect(f, func(n ast.Node) bool { switch x := n.(type) { case *ast.FuncDecl: processFunction(x) } return true }) 然后,processFunction()如下所示: func processFunction(e *ast.FuncDecl) {
go/ast
包解析代码中的函数调用
为此,我首先查找所有函数调用,如:
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.FuncDecl:
processFunction(x)
}
return true
})
然后,processFunction()如下所示:
func processFunction(e *ast.FuncDecl) {
// Save wrapper function name
f := e.Name.Name
for _, expression := range e.Body.List {
logrus.Printf("Current stmt: %#v", expression)
pkg := expression.(*ast.ExprStmt).X.(*ast.CallExpr).Fun.(*ast.SelectorExpr).X.(*ast.Ident).Name
fn := expression.(*ast.ExprStmt).X.(*ast.CallExpr).Fun.(*ast.SelectorExpr).Sel.Name
fcall := fmt.Sprintf("%s.%s", pkg, fn)
logrus.Printf("Yay. found my function call: ", fcall)
}
}
这段代码的问题是,如果在AST中找不到特定的层次结构,程序就会崩溃。我知道我们可以通过
x, ok := x.(type)
但是,如果我这样做每一个转换,我的代码将是巨大的。当然,在这种情况下尝试使用它是失败的
pkg, ok := expression.(*ast.ExprStmt).X.(*ast.CallExpr).Fun.(*ast.SelectorExpr).X.(*ast.Ident).Name
if !ok {
continue
}
错误:
./parser.go:41: assignment count mismatch: 2 = 1
有没有一种简洁的方法可以完成这一系列的转换,并且在没有找到这个层次结构的情况下也会优雅地失败?据我所知,没有任何方法可以链接类型断言。但您可以通过将重复代码提取到其自身的函数中来简化此特定示例
func fnSelExpr(s ast.Stmt) (*ast.SelectorExpr, bool) {
if xs, ok := s.(*ast.ExprStmt); ok {
if cx, ok := xs.X.(*ast.CallExpr); ok {
return cx.Fun.(*ast.SelectorExpr)
}
}
return nil, false
}
然后你可以像这样简化你的processFunction
func processFunction(e *ast.FuncDecl) {
// Save wrapper function name
f := e.Name.Name
for _, expression := range e.Body.List {
logrus.Printf("Current stmt: %#v", expression)
sx, ok := fnSelExpr(expression)
if !ok {
continue
}
var pkg string
if id, ok := sx.X.(*ast.Ident); ok {
pkg = id.Name
}
fn := sx.Sel.Name
fcall := fmt.Sprintf("%s.%s", pkg, fn)
logrus.Printf("Yay. found my function call: ", fcall)
}
}
这是使用monad实用的情况之一(不是简单地看起来很酷):实现一个
other
monad,您的表达式将转换为pkg:=other.of(expression).Bind(GetExpStmt).Bind(GetX).Bind(…)
。它将返回一个值,该值可以是您想要的值,也可以是一个error/null/a结构和其他数据,您可以优雅地处理该值。