好的,所以看看使用go / types,go / parser ......等等来生成一些代码;但需要确定实现我已经想到的特定接口的所有结构,但是,如果结构函数上的结构定义与使用types.Implements不匹配。
确定代码示例:
获取界面
package ifacepkg
const interfacePkg = `package ifacepkg
type MyInterface interface {
MyFunction() error
}
`
func getIface() *types.Interface {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "iface.go", interfacePkg, 0)
if err != nil {
panic(err)
}
config := &types.Config{
Error: func(e error) {
fmt.Println(e)
},
Importer: importer.Default(),
}
info := types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
}
pkg, e := config.Check("genval", fset, []*ast.File{f}, &info)
if e != nil {
fmt.Println(e)
}
return pkg.Scope().Lookup("MyInterface").Type().Underlying().(*types.Interface)
}
测试文件
package test
import "ifacepkg"
// User struct
type User struct {
FirstName string
LastName string
}
func (u User) MyFunction() error {
return nil
}
var _ ifacepkg.MyInterface = &User{}
加载测试文件&试图查看User是否实现MyInterface
fset := token.NewFileSet()
pkgs, e := parser.ParseDir(fset, "./test", nil, 0)
if e != nil {
log.Fatal(e)
// return
}
var astf []*ast.File
for _, pkg := range pkgs {
fmt.Printf("package %v\n", pkg.Name)
for fn, f := range pkg.Files {
fmt.Printf("file %v\n", fn)
astf = append(astf, f)
}
}
config := &types.Config{
Error: func(e error) {
fmt.Println(e)
},
Importer: importer.Default(),
}
info := types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
}
pkg, e := config.Check(path, fset, astf, &info)
if e != nil {
fmt.Println(e)
}
vIface := getIface()
fmt.Println(vIface)
scope := pkg.Scope()
for _, name := range scope.Names() {
obj := scope.Lookup(name)
_, ok := obj.Type().Underlying().(*types.Struct)
imp := types.Implements(obj.Type(), vIface)
fmt.Println(obj.Name(), ok, imp)
}
好的,所以fmt.Println(obj.Name(),ok,imp)打印用户真正的所有好!但是,如果我从
更改源文件功能func (u User) MyFunction() error {
到
func (u *User) MyFunction() error {
现在打印User true false
所以函数类型。实现报告用户没有实现MyInterface,这不是真的。
所以我的问题是:type.Implements方法是否有问题,或者在调用该函数之前我是否需要对我的对象做些什么。
答案
可以解决我自己的问题,将代码的最后部分更改为
scope := pkg.Scope()
for _, name := range scope.Names() {
obj := scope.Lookup(name)
_, ok := obj.Type().Underlying().(*types.Struct)
ptr := types.NewPointer(obj.Type())
imp := types.Implements(ptr.Underlying(), vIface)
fmt.Println(obj.Name(), ok, imp)
}
适用于指针和非指针接收器
答案 0 :(得分:1)
您的编译器告诉您的是真的。 *输入!=输入Go。如果您希望*User
实现您的界面,则接收方必须为*User
,如果您希望它为User
,那么它必须为User
。我真的不知道如何解释它... Go的类型系统是严格的,并且它们是相同的。如果您为指针类型(u *User) MyFunction()
定义了ptr := &MyUser
,那么您可以更实际地看到这一点,然后检查MyUser
和ptr
是否实现了接口,ptr
将, MyUser
不会。