go - Golang - 创建一个与传递的相同类型的对象
问题描述
我正在尝试构建一个通用函数,它将输入(以 JSON 格式)解析为指定的结构。根据传递给函数的参数,结构在运行时可能会有所不同。我目前正在尝试通过传递正确类型的对象并使用 reflect.New() 创建相同类型的新输出对象来实现这一点。
然后我将 JSON 解析为这个对象,并扫描这些字段。
如果我创建对象并在代码中指定类型,那么一切正常。如果我传递一个对象并尝试创建一个副本,我会在几步之后得到一个“无效的间接”错误(参见代码)。
import (
"fmt"
"reflect"
"encoding/json"
"strings"
)
type Test struct {
FirstName *string `json:"FirstName"`
LastName *string `json:"LastName"`
}
func genericParser(incomingData *strings.Reader, inputStructure interface{}) (interface{}, error) {
//******* Use the line below and things work *******
//parsedInput := new(Test)
//******* Use vvv the line below and things don't work *******
parsedInput := reflect.New(reflect.TypeOf(inputStructure))
decoder := json.NewDecoder(incomingData)
err := decoder.Decode(&parsedInput)
if err != nil {
//parsing error
return nil, err
}
//******* This is the line that generates the error "invalid indirect of parsedInput (type reflect.Value)" *******
contentValues := reflect.ValueOf(*parsedInput)
for i := 0; i < contentValues.NumField(); i++ {
//do stuff with each field
fmt.Printf("Field name was: %s\n", reflect.TypeOf(parsedInput).Elem().Field(i).Name)
}
return parsedInput, nil
}
func main() {
inputData := strings.NewReader("{\"FirstName\":\"John\", \"LastName\":\"Smith\"}")
exampleObject := new(Test)
processedData, err := genericParser(inputData, exampleObject)
if err != nil {
fmt.Println("Parsing error")
} else {
fmt.Printf("Success: %v", processedData)
}
}
If I can't create a replica of the object, then a way of updating / returning the one supplied would be feasible. The key thing is that this function must be completely agnostic to the different structures available.
解决方案
reflect.New
isn't a direct analog to new
, as it can't return a specific type, it only can return a reflect.Value
. This means that you are attempting to unmarshal into a *reflect.Value
, which obviously isn't going to work (even if it did, your code would have passed in **Type
, which isn't what you want either).
Use parsedInput.Interface()
to get the underlying value after creating the new value to unmarshal into. You then don't need to reflect on the same value a second time, as that would be a reflect.Value
of a reflect.Value
, which again isn't going to do anything useful.
Finally, you need to use parsedInput.Interface()
before you return, otherwise you are returning the reflect.Value
rather than the value of the input type.
For example:
func genericParser(incomingData io.Reader, inputStructure interface{}) (interface{}, error) {
parsedInput := reflect.New(reflect.TypeOf(inputStructure).Elem())
decoder := json.NewDecoder(incomingData)
err := decoder.Decode(parsedInput.Interface())
if err != nil {
return nil, err
}
for i := 0; i < parsedInput.Elem().NumField(); i++ {
fmt.Printf("Field name was: %s\n", parsedInput.Type().Elem().Field(i).Name)
}
return parsedInput.Interface(), nil
}
推荐阅读
- c# - 开始调试时在 Home/Error 上自动重定向
- javascript - 无法从量角器下载测试用例返回 chrome://downloads/ 列表
- css - 在 vue js 项目的 css 验证器中找不到样式表
- c# - ASP.NET C# 如何从 SQL Server 检索数据并将多行数据转换为逗号分隔的一行?
- docker - 尝试使用 wso2 登录 dockerized 应用程序时出现“提供的授权授予无效”错误
- php - 如何使用 php 动态更改 oracle 名称空间对象名称
- reactjs - 反应,反应选择占位符
- android - 正则表达式在 kotlin 中拆分字符串
- javascript - Vue - 在自定义指令中实例化组件
- android - Android Studio RecyclerView 导入问题