【问题标题】:Golang - create an object of the same type as passedGolang - 创建一个与传递的相同类型的对象
【发布时间】:2020-06-02 17:34:09
【问题描述】:

我正在尝试构建一个通用函数,它将输入(以 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)
    }
}

如果我无法创建对象的副本,那么一种更新/返回所提供对象的方法是可行的。关键是这个函数必须与可用的不同结构完全无关。

【问题讨论】:

    标签: go types


    【解决方案1】:

    reflect.New 不是new 的直接模拟,因为它不能返回特定类型,它只能返回reflect.Value。这意味着您正试图解组到 *reflect.Value,这显然是行不通的(即使这样做,您的代码也会在 **Type 中传递,这也不是您想要的)。

    在创建要解组的新值后,使用parsedInput.Interface() 获取基础值。然后,您无需再次考虑相同的值,因为这将是 reflect.Value 或 reflect.Value,这同样不会做任何有用的事情。

    最后,你需要在返回之前使用parsedInput.Interface(),否则你返回的是reflect.Value而不是输入类型的值。

    例如:

    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
    }
    

    https://play.golang.org/p/CzDrj6sgQNt

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-23
      • 2012-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多