为了账号安全,请及时绑定邮箱和手机立即绑定

从界面获取反射结构

从界面获取反射结构

Go
MMMHUHU 2022-10-04 16:41:41
有这个函数的获取类型的值,但我尝试这个,从来没有得到反射.struct:type Test struct {    Code int       Name string}func main(){    test := getTest()    data, err := getBytes(slice...)    sanitizedFile := bytes.Split(data, []byte("\r\n"))    err = Unmarshal(sanitizedFile[0], &test)}func getTest() interface{} {    return Test{}}有了这个代码,我无法从Unmarshall func中的v参数中获取replecet.structfunc Unmarshal(data []byte, v interface{}) error {    rv := reflect.ValueOf(v)    if rv.Kind() == reflect.Ptr {        rvElem := rv.Elem()                switch rvElem.Kind() {        case reflect.Struct:           // implement me        }    }    return ErrInvalid}我想知道我是否可以以某种方式找出接口是否属于结构类型或访问该结构的值。
查看完整描述

2 回答

?
侃侃尔雅

TA贡献1801条经验 获得超15个赞

我认为这里真正的问题可以通过这句话来说明:


我想知道我是否可以以某种方式找出接口是否属于结构类型或访问该结构的值。


接口值不是“结构类型”。从不!接口值可以包含类型为某种结构的值,但它不是该类型的值。它只包含一个。这类似于您从亚马逊获得的盒子1可以包含开瓶器的方式,但盒子永远不是开瓶器。


给定某个接口类型的非 nil 值,您知道您有一个实现 的方法的值。由于 是空的方法集,所有类型都实现它,因此给定类型(仍然是非 nil)值,您有一个不实现任何方法的值。这本身根本没有用:这意味着你不能调用任何方法,这意味着你不能做任何类似方法的事情。interface III{}interface{}


但是,仅仅因为你不能做任何事情,方法-y并不意味着你根本不能做任何事情。任何接口值(无论接口类型如何)都可以在其上使用类型断言:


iv := somethingThatReturnsAnInterface()

cv := iv.(struct S) // assert that iv contains a `struct S`

如果确实包含一个值(如果打开它后,这就是盒子里的内容),那么这种类型断言不会惊慌失措,并且最终会得到类型的具体值。如果不需要 panic,我们可以使用表单或类型开关。所有这些(包括崩溃的版本)都通过检查接口内的值的类型来工作。ivstruct Scvstruct Scv, ok := iv.(struct S)


这个——或者更准确地说,Go语言的定义方式——告诉我们的是,“盒子”实际上包含两样东西:interface


具体类型,以及

一个具体的价值。

好吧,也就是说,除非它持有<无,无>对,在这种情况下是真的。请注意,该测试实际上测试了这两个部分。iv == niliv == nil


如果Go有一个语法,我们可以写一些类似的东西,以获得两个独立的部分。但我们不能那样做。我们必须使用类型断言、类型切换或 。所以,回到这个:iv.typeiv.valuereflect


我想知道我是否可以以某种方式找出接口是否是结构类型


我们可以看到,问题本身只是有点畸形。我们不想知道接口值是否具有此类型。我们想知道非nil接口的持有值是否属于这种类型,就好像我们可以直接检查一样。iv.typeiv.value


如果一组有限的可能类型,则可以使用类型开关构造,并枚举所有允许的可能性:


switch cv := iv.(type) {

case struct S:

    // work with cv, which is a struct S

case *struct S:

    // work with cv, which is a *struct S

// add more cases as appropriate

}

如果您需要更通用的内容,而不是执行上述操作,我们最终将使用该包:reflect


tv := reflect.TypeOf(iv)

艺术


vv := reflect.ValueOf(iv)

后者实际上是更有用的形式,因为捕获伪场和伪场。vviv.typeiv.value


正如 mkopriva 在注释中指出的那样,在您的示例代码中,具有 类型 ,类型 也是如此。在大多数情况下,这不是一个好主意:您只想直接传递值。testinterface{}&test*interface{}interface{}


若要允许被调用函数将对象设置为新值,您需要将指向该对象的指针作为接口值传递。您不希望传递指向接口的指针,同时让接口将结构“放在框中”。您需要一个可以调用的 ,并且要获取一个,您需要跟随 一个 on the,它是指向结构的指针(而不是指向接口的指针)。reflect.ValueSet()elemreflect.Value



查看完整回答
反对 回复 2022-10-04
?
一只萌萌小番薯

TA贡献1795条经验 获得超7个赞

也许你需要的是类型断言?

t, 确定 := v.(我的结构)

https://tour.golang.org/methods/15

在任何情况下,此代码都会打印“结构”:

 type tt struct {}


    var x tt

    var z interface{}

    z = x

    v := reflect.ValueOf(z).Kind()

    fmt.Printf("%v\n", v)

有关使用反射设置结构字段的值,请参阅以下内容:

使用反射,如何设置结构字段的值?


查看完整回答
反对 回复 2022-10-04
  • 2 回答
  • 0 关注
  • 74 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信