如果struct实现接口

时间:2015-12-28 17:20:37

标签: parsing variables go 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 {

现在打印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)
}

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

1 个答案:

答案 0 :(得分:1)

您的编译器告诉您的是真的。 *输入!=输入Go。如果您希望*User实现您的界面,则接收方必须为*User,如果您希望它为User,那么它必须为User。我真的不知道如何解释它... Go的类型系统是严格的,并且它们是相同的。如果您为指针类型(u *User) MyFunction()定义了ptr := &MyUser,那么您可以更实际地看到这一点,然后检查MyUserptr是否实现了接口,ptr将, MyUser不会。