登录
首页 >  Golang >  Go问答

如何使用reflect.NewAt在空接口上创建新值?

来源:stackoverflow

时间:2024-02-17 23:18:25 113浏览 收藏

目前golang学习网上已经有很多关于Golang的文章了,自己在初次阅读这些文章中,也见识到了很多学习思路;那么本文《如何使用reflect.NewAt在空接口上创建新值?》,也希望能帮助到大家,如果阅读完后真的对你学习Golang有帮助,欢迎动动手指,评论留言并分享~

问题内容

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
    "unsafe"
)

type Stu struct {
    Name string `json:"name"`
}

func MakeStu() interface{} {
    return Stu{
        Name: "Test",
    }
}

func main() {
    jsonData := []byte(`{"name":"New"}`)
    t1 := MakeStu()
    t2 := MakeStu()
    t3 := MakeStu()

    json.Unmarshal(jsonData, &t1)
    fmt.Println(t1) //Type of t1 becomes map[string]interface{} instead of struct Stu

    newPointer := reflect.New(reflect.ValueOf(t2).Type()).Interface()
    json.Unmarshal(jsonData, newPointer)
    fmt.Println(newPointer) //It works,but it need allocate memory to hold temp new variable

    brokenPointer := reflect.NewAt(reflect.ValueOf(t3).Type(), unsafe.Pointer(&t3)).Interface()
    json.Unmarshal(jsonData, brokenPointer)
    fmt.Println(brokenPointer) // I want to get the pointer of original type based on the existed variable t3,but it crashes.
}

如果我在编码时不知道interface{}的具体类型,就无法使用interface.(type)进行强制转换。 那么如何在interface{}上使用reflect.newat呢?

如果有一个接口,其中包含一个返回interface{}的方法,其具体类型是struct,但我在编码时无法确定struct的类型。我需要使用 json.unmarshal 来解码由 json 编码的数据。我不想获得 map[string]interface{} ,所以我需要将接收者的类型设置为 interface{} 的具体类型的指针。使用reflect.new 很简单,但会消耗额外的内存,因此我很好奇如何将reflect.newat 与现有接口一起使用{}。


正确答案


我想花几句话解释一下问题所在。

我们无法控制的函数 makestu() 返回空接口 - 不是具体类型。这将使具体类型对 json.unmarshal() “不可见”,并且 json.unmarshal() 将其视为空接口,而不是具体类型 stu。我们必须以某种方式将具体类型传达给解组器。

我会用类型开关解决这个问题:

func main() {
    jsondata := []byte(`{"name":"new"}`)
    t1 := makestu()

    switch c := t1.(type) {
    default:
        _ = json.unmarshal(jsondata, &c)
        t1 = c
    }

    fmt.println(t1)
}

类型开关将空接口转换为具体类型,并且 json.unmarshal() 会将其视为具体类型。您可能仍然会有额外的分配,但代码更具可读性,并且您不依赖于反射。

如果我真的很喜欢冒险,我会添加一个辅助函数,接受指向空接口的指针,如下所示:

func unmarshal(data []byte, i *interface{}) (err error) {
    switch c := (*i).(type) {
    default:
        err = json.unmarshal(data, &c)
        *i = c
    }

    return err
}

这将启用这样的用法:

    jsonData := []byte(`{"name":"New"}`)
    t1 := MakeStu()
    unmarshal(jsonData, &t1)

这对我来说看起来很干净,并且不涉及反射,但它没有像您自己建议的那样使用 reflect.newat() 。我希望您发现我的建议仍然有用。

理论要掌握,实操不能落!以上关于《如何使用reflect.NewAt在空接口上创建新值?》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>