从接口获取 reflect.struct

get reflect.struct from interface

你好,我有这个函数来获取值类型,但我尝试了这个,但永远无法获取 reflect.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 参数中获取 reflecet.struct
func 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
}

我想知道我是否能以某种方式查明接口是否为结构类型或访问该结构的值。

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

t,好的 := v.(myStruct)

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

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

    type tt struct {}

    var x tt
    var z interface{}
    z = x
    v := reflect.ValueOf(z).Kind()
    fmt.Printf("%v\n", v)

并查看此内容以使用反射设置结构字段的值:

Using reflect, how do you set the value of a struct field?

我认为这句话说明了真正的问题:

I would like to know if I can somehow find out if an interface is of type struct or access the values ​​of that struct.

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

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

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

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

如果 iv 实际上包含一个 struct S 值——如果打开盒子后里面就是这个值——那么这个类型断言 不会 恐慌,cvstruct S 类型的具体值结束。如果不希望出现恐慌,我们可以使用 cv, ok := iv.(struct S) 形式或类型开关。所有这些——包括出现 panic 的版本——都是通过 检查接口内值的类型 .

来工作的

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

  • 具体类型,并且
  • 一个具体的值。

嗯,也就是说,除非它持有 对,在这种情况下 iv == nil 为真。请注意 iv == nil 测试实际上测试了 两个部分 .

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

I would like to know if I can somehow find out if an interface is of type struct

我们可以看到问题本身有点畸形。我们不想知道接口值 是否具有 这种类型。我们想知道一个非 nil 接口的 held value 是否是 of 这种类型,就好像我们可以检查 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)

后者实际上是更有用的形式,因为 vv 捕获了 iv.type 伪字段 iv.value 伪字段场.

由于 test 在您的示例代码中具有类型 interface{},因此 &test 具有类型 *interface{}。在大多数情况下,这不是一个好主意:您只想直接传递 interface{} 值。

为了允许调用的函数对象设置为新值,您需要将指向对象的指针传递为接口值。您不希望在让接口按原样将结构“放在盒子里”的同时将指针传递给接口。您需要一个可以在其上调用 Set()reflect.Value,要获得一个,您需要在 reflect.Value 上跟随一个 elem,它是指向结构的指针(不是指向接口的指针。

有一个更完整的示例 here on the Go Playground


1这部分暗指某些其他编程语言中的“盒装值”(参见 What is boxing and unboxing and what are the trade offs?),但部分是字面意思。不过,不要将 Go 的接口误认为是 Java 的盒装值:它们根本不一样。