深入理解Golang中的类型解析机制
深入理解Golang中的类型解析机制
我正在尝试编写一个针对特定类型进行操作的定制化 linter。但我似乎对 Go 的类型系统存在一些误解。在下面的示例中,我解析了一段声明了类型为 time.Time 的变量 Foo 的示例代码。然而,当我使用 types.Identical() 将 Foo 的类型与 time.Time 进行比较时,它返回了 false。这是为什么呢?如果我的目标是找到涉及 time.Time 类型的表达式,我是否应该使用不同于 types.Identical() 的方法来识别它们?
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
"golang.org/x/tools/go/packages"
)
const example = `package main
import "time"
var Foo time.Time
func main() {
}`
// 基于 https://github.com/golang/example/tree/master/gotypes#an-example
func ParseExamplePackage() *types.Package {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "example.go", example, 0)
if err != nil {
panic(err)
}
conf := types.Config{Importer: importer.Default()}
pkg, err := conf.Check("example", fset, []*ast.File{f}, nil)
if err != nil {
panic(err)
}
return pkg
}
func ParseTimePackage() *packages.Package {
cfg := &packages.Config{
Mode: packages.LoadAllSyntax,
}
loadedPackages, err := packages.Load(cfg, "time")
if err != nil {
panic(err)
}
return loadedPackages[0]
}
func main() {
timePkg := ParseTimePackage()
timeObject := timePkg.Types.Scope().Lookup("Time")
examplePkg := ParseExamplePackage()
fooObject := examplePkg.Scope().Lookup("Foo")
fmt.Printf("time type: %s\n", timeObject.Type().String()) // time.Time
fmt.Printf("foo type: %s\n", fooObject.Type().String()) // time.Time
fmt.Printf("identical: %t\n", types.Identical(timeObject.Type(), fooObject.Type())) // false
}
更多关于深入理解Golang中的类型解析机制的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
你的代码唯一的问题是,你将你的代码和 time 包分开加载了。types.Identical 中的某些检查会检查 *types.Package == *types.Package,如果包是分开解析的,这个比较就会得到 false。如果你把你的示例代码放到一个包里,并和 time 包一起加载,它就能正常工作:
package main
import (
"fmt"
"go/types"
"golang.org/x/tools/go/packages"
)
func ParseTestAndTimePackages() (test, time *packages.Package) {
cfg := &packages.Config{
Mode: packages.LoadAllSyntax,
}
loadedPackages, err := packages.Load(cfg, "forum.golangbridge.org/understanding-parsed-go-types_20561/test", "time")
if err != nil {
panic(err)
}
if len(loadedPackages) != 2 {
panic("only loaded 1 pkg")
}
if loadedPackages[0].PkgPath == "time" {
return loadedPackages[1], loadedPackages[0]
}
return loadedPackages[0], loadedPackages[1]
}
func main() {
testPkg, timePkg := ParseTestAndTimePackages()
timeObject := timePkg.Types.Scope().Lookup("Time")
fooObject := testPkg.Types.Scope().Lookup("Foo")
fmt.Printf("time type: %s\n", timeObject.Type().String()) // time.Time
fmt.Printf("foo type: %s\n", fooObject.Type().String()) // time.Time
fmt.Printf("identical: %t\n", types.Identical(timeObject.Type(), fooObject.Type())) // true
}
更多关于深入理解Golang中的类型解析机制的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


