Go 如何将reflect.Value结构类型断言回我知道它实现的接口?

Go 如何将reflect.Value结构类型断言回我知道它实现的接口?,go,reflection,go-reflect,Go,Reflection,Go Reflect,我最近在go中编写了一些审计流程。大多数情况下,这只是将任意结构拆分的反射。存在一个可用于对象相等的接口。并不是所有被拆分的东西都实现了这个接口,并且可以在任意类型之间进行比较(对象相等并不意味着类型相等) 由于被比较的对象不需要是相同的类型,因此在某些情况下,某个对象一边是指针,另一边是值(*string vs string或*ChickenBox vs BoxOfChicken)。我只是在遇到指针/接口值时取消对它们的引用,因此完成后的比较很简单 我的问题是,一旦我取消了对指针/接口的引用,

我最近在go中编写了一些审计流程。大多数情况下,这只是将任意结构拆分的反射。存在一个可用于对象相等的接口。并不是所有被拆分的东西都实现了这个接口,并且可以在任意类型之间进行比较(对象相等并不意味着类型相等)

由于被比较的对象不需要是相同的类型,因此在某些情况下,某个对象一边是指针,另一边是值(*string vs string或*ChickenBox vs BoxOfChicken)。我只是在遇到指针/接口值时取消对它们的引用,因此完成后的比较很简单

我的问题是,一旦我取消了对指针/接口的引用,我似乎就无法向父指针/接口实现的接口键入assert

下面是一个示例(游乐场:)演示了这一点:

package main

import (
    "fmt"
    "reflect"
)

// ID interface
type IHasID interface {
    GetID() string
    SetID(id string)
}

// implementing type
type HasID struct {
    ID string `bson:"_id,omitempty"`
}

func (be *HasID) GetID() string {
    return be.ID
}
func (be *HasID) SetID(id string) {
    be.ID = id
}

// static comparison reflect.Type of IHasID
var idType = reflect.TypeOf((*IHasID)(nil)).Elem()

func main() {
    testy := struct {
        HasID
        Somefield int
    }{
        HasID{
            ID: "testymctest",
        },
        4,
    }

    id, _ := GetIDFrom(reflect.ValueOf(testy))
    fmt.Printf("ID: %v\n", id)
}

// check if the reflect.Value implements IHasID
func ImplementsID(x reflect.Value) bool {
    switch x.Kind() {
    case reflect.Interface, reflect.Ptr:
        if x.IsValid() && !x.IsNil() {
            return ImplementsID(x.Elem())
        }
    case reflect.Struct:
        if x.IsValid() {
            return reflect.PtrTo(x.Type()).Implements(idType)
        }
    }
    return false
}

// check and get the reflect.Value's ID
func GetIDFrom(x reflect.Value) (string, bool) {
    switch x.Kind() {
    case reflect.Ptr, reflect.Interface:
        if x.IsValid() && !x.IsNil() {
            return GetIDFrom(x.Elem())
        }
    case reflect.Struct:
        if x.IsValid() && ImplementsID(x) {
            // not using val,ok syntax to demo issue, if it gets here it should
            // implement ID since we did the check in the if statement above
            val := x.Interface().(IHasID)
            return val.GetID(), true
        }
    }
    return "", false
}
我的理解是,接口由两部分组成()。在reflect中,这由reflect.Type(广义方法)和reflect.Value(广义数据)表示。在演示中,我们成功评估了传递的reflect.Value的reflect.Type是否实现了第67行的接口:

if x.IsValid() && ImplementsID(x) {
这是因为在第53行,我们可以使用reflect.PtrTo重建与接口的关系:

return reflect.PtrTo(x.Type()).Implements(idType)
我无法在reflect.Value端复制这个过程(在reflect.Type端)。因此,在第70行,我们只需要底层结构(没有方法):

这失败了,我一直找不到任何语法,使我能够做什么似乎已经在反射方面是可能的;回到针对满足断言接口的结构定义的方法(我认为reflect.Type可能只是针对缓存接口存储工作,到目前为止,我已经丢失了structs方法)


我有一个可行的解决方案,在做任何工作之前,它只是强制执行指针/接口的存在,但这让我觉得我遗漏了什么。如果reflect.Value的reflect.Type可以成功地找到接口,那么在reflect.Value方面肯定有类似的事情可以做?

GetID方法需要一个指针接收器,但是您正在对一个结构值进行操作。由于该值不可寻址,因此不能调用
GetID
方法,也不能调用
Addr()
获取指向该值的指针

这与无法编译的原因相同:

调用
GetIDFrom

id, _ := GetIDFrom(reflect.ValueOf(&testy))

然后,您应该首先检查指针是否实现了接口,然后再使用
Elem()
解除对它的引用以检查结构类型。

我无法像在reflect.type端那样使该值可寻址?@Imunro,no,但您只需要将初始值作为指针传递。@lmunro:无法获取无法寻址值的地址。您可以使用
reflect.new
创建一个指向结构的新指针,并将旧值复制到中,但从一开始就使用指针更容易。
hid := HasID{ID: "testID"}
_ = IHasID(hid)
id, _ := GetIDFrom(reflect.ValueOf(&testy))