2 回答
![?](http://img1.sycdn.imooc.com/545863f50001df1702200220-100-100.jpg)
TA贡献1788条经验 获得超4个赞
通过静态分析查找表达式的类型非常重要,有时甚至是不可能的,有关详细信息,请参阅Golang static identifier resolution。
用例是我有一个在整个(非常大的)代码库中常用的通用函数,并且想引入该函数的新类型安全版本。为此,我希望自动确定函数的“类型”并相应地重构它:
// old
DB.InsertRow(person)
// new
Person.InsertRow(person)
仅出于重构目的,我认为不值得费心去实施它。
您可以做的是DB.InsertRow()临时更改签名以仅接受特定类型,例如int您确定未在任何地方使用的自定义类型(例如type tempFoo struct{})。
为了什么目的?这样做,编译器将为您完成艰苦的工作。您将看到错误消息准确显示您的代码库试图传递给的类型DB.InsertRow(),所以我想说任务已完成。
例如这段代码编译:
func doSomething(x interface{}) {}
func main() {
doSomething(image.Pt(1, 2))
doSomething("abc")
doSomething(image.Rect) // image.Rect is a function which we don't call,
// so we're passing a value of a function type here
}
如果我们改变doSomething():
func doSomething(x int) {}
我们从编译器中得到我们正在寻找的类型:
./prog.go:10:14: 不能使用 image.Pt(1, 2)(image.Point类型的值)作为 doSomething 参数中的 int 类型
./prog.go:11:14: 不能在 doSomething 的参数中使用“abc”(无类型字符串常量)作为 int 值
./prog.go:12:14: 不能使用 image.Rect(类型func(x0 int, y0 int, x1 int, y1 int) image.Rectangle 的值)作为 doSomething 参数中的 int 类型
![?](http://img1.sycdn.imooc.com/54584cc500019c5b02200220-100-100.jpg)
TA贡献1876条经验 获得超6个赞
使用Golang static identifier resolution to use的建议golang.org/x/tools/go/types
,我发现这对golang.org/x/tools/go/analysis
包来说非常简单,它具有可用的类型信息以及解析的 ast。
这是我的解决方案:
package rewriter
import (
"go/ast"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
func run(pass *analysis.Pass) (interface{}, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.CallExpr)(nil),
}
inspect.Nodes(nodeFilter, func(node ast.Node, push bool) bool {
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return true
}
funcExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
// check method name
if funcExpr.Sel.Name != "doSomething" {
return true
}
for _, arg := range callExpr.Args {
// lookup type of the arg
argType := pass.TypesInfo.Types[arg].Type
if argType.String() == "*rewriter.Person" {
// do whatever you want here
}
}
return false
})
return nil, nil
}
可以扩充它以查看方法的接收者并根据需要添加重构逻辑(使用analysis.Diagnostic)。
- 2 回答
- 0 关注
- 77 浏览
添加回答
举报