Home  >  Article  >  Backend Development  >  How to use reflect.NewAt on interface{}?

How to use reflect.NewAt on interface{}?

WBOY
WBOYforward
2024-02-09 14:00:24921browse

How to use reflect.NewAt on interface{}?

php editor Xinyi introduces you how to use reflect.NewAt on interface{}. reflect.NewAt is a reflection library function in Go language, used to create a new instance on a given interface type. By using reflect.NewAt, we can dynamically create and initialize a new interface instance without specifying a specific type at compile time. This gives us greater flexibility and dynamics, allowing the code to be more versatile and extensible. The following will give you a detailed explanation of how to use reflect.NewAt to create an instance on interface{}.

Question content

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.
}

If I don't know the specific type of interface{} when coding, I can't use interface.(type) to cast. So how to use reflect.newat on interface{}?

If there is an interface that contains a method that returns interface{}, its specific type is struct, but I cannot determine the type of struct when coding. I need to use json.unmarshal to decode data encoded by json. I don't want to get map[string]interface{} , so I need to set the type of the receiver to a pointer to a concrete type of interface{} . Using reflect.new is simple, but consumes extra memory, so I'm curious how to use reflect.newat with an existing interface{}.

Solution

I would like to spend a few words explaining the problem.

Functions we have no control over makestu() Returns an empty interface - not a concrete type. This will make the concrete type "invisible" to json.unmarshal() and json.unmarshal() treat it as an empty interface rather than a concrete type stu. We have to communicate the concrete type to the unmarshaller somehow.

I would solve this problem using type switches:

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

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

    fmt.println(t1)
}

The type switch converts the empty interface to a concrete type, and json.unmarshal() will treat it as a concrete type. You may still have extra allocations, but the code is more readable and you don't rely on reflection.

If I were feeling really adventurous, I would add a helper function that accepts a pointer to an empty interface, like this:

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

    return err
}

This will enable usage like this:

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

This looks clean to me and doesn't involve reflection, but it doesn't use reflect.newat() as you yourself suggested. I hope you find my advice still useful.

The above is the detailed content of How to use reflect.NewAt on interface{}?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete