繁体   English   中英

go / types查找struct是否实现接口

[英]go/types finding if struct implements interface

好吧所以看看使用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 {

它现在打印用户真假

所以函数类型。实现报告用户没有实现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)
}

它适用于指针和非指针接收器

你的编译器告诉你的是真的。 *输入!=输入Go。 如果你想让*User实现你的界面,那么接收方法必须是*User ,如果你想让它成为User那么它需要是User 我真的不知道怎么解释它... Go的类型系统是严格的,那些不一样。 你可以更实际地看到这个,如果你有(u *User) MyFunction()为指针类型定义的(u *User) MyFunction()执行ptr := &MyUser然后检查MyUserptr实现了接口, ptr将是, MyUser不会。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM