将json.RawMessage解组为反射切片。

huangapple go评论77阅读模式
英文:

Unmarshal json.RawMessage to a reflected slice

问题

在最后一部分,你遇到了一个异常的原因是你试图将json.RawMessage字段解析为一个reflect.Value类型的Go值,但是json.Unmarshal函数无法直接将数组解析为reflect.Value类型。

为了解决这个问题,你可以使用json.Unmarshal函数将json.RawMessage解析为一个临时的切片,然后使用反射将切片的元素逐个添加到reflect.Value类型的切片中。下面是修改后的代码:

// ...

// 创建一个临时的切片用于解析json.RawMessage
var tempSlice []json.RawMessage
err = json.Unmarshal(command.Items, &tempSlice)
if err != nil {
    log.Fatalln("error:", err)
}

// 使用反射将切片的元素逐个添加到reflect.Value类型的切片中
for _, item := range tempSlice {
    newItem := reflect.New(itemtyp).Interface()
    err = json.Unmarshal(item, newItem)
    if err != nil {
        log.Fatalln("error:", err)
    }
    rv = reflect.Append(rv, reflect.ValueOf(newItem).Elem())
}

// ...

这样修改后,你就可以成功解析json.RawMessage字段并将其转换为reflect.Value类型的切片了。

英文:

In the following sample, i am trying to Unmarshal a json.RawMessage into a slice using reflection to figure out the type of the items in the json.RawMessage, the json.RawMessage always represents an array of a specific type, the name of the type is included in the json and a pointer to it is retrieved from a map[string]interface{}

 type command struct {
    	Action   *string
    	Type     *string
    	Items    json.RawMessage //because i need to figure out the Type field value first, its always an array of a single type
    }
    
//a sample model
    type Chicken struct {
    	Id        *int
    	Name      *string
    	EggColor  *string
    }
    
    //this map contains a pointer to each needed struct using reflection i can get the type and make a SliceOf it
    var ModelRegistery map[string]interface {}
    
    func main(){
    
        //register the Chicken type to retrieve a pointer to it using a string key
    	var chickenPtr *Chicken
    	ModelRegistery = make(map[string]interface {})
    	ModelRegistery["Chicken"] = chickenPtr
    
        //some json for testing
    	cJson := []byte(`{"Action":"BURN",
    	                  "Type":"Chicken",
    	                  "Items":[{"Id":1,"Name":"B","EggColor":"D"},
    	                           {"Id":2,"Name":"M","EggColor":"C"}]}`)
    
    
    	var command command
    	err := json.Unmarshal(cJson,&command)
    	if err != nil {
    		log.Fatalln("error:", err)
    	}
    
        //get the type from the model registry and reflect it
    	itemtyp := reflect.TypeOf(ModelRegistery[(*command.Type)]).Elem()
        //create a slice of the type
    	itemslice := reflect.SliceOf(itemtyp)
    	rv := reflect.MakeSlice(itemslice, 0, 2)
         
        //now when trying to unmarshal the json.RawMessage field i get an exception
      	err = json.Unmarshal(command.Items,&rv)
    	if err != nil {
    		log.Fatalln("error:", err) //error: json: cannot unmarshal array into Go value of type reflect.Value
    	}
    }

the question is, what am i doing wrong in the last part? why do i get the exception?

json: cannot unmarshal array into Go value of type reflect.Value

here is a goplay
http://play.golang.org/p/63dxgnPFz_

答案1

得分: 3

你需要将interface{}传递给unmarshal函数,而不是reflect.Value。

更改以下部分似乎可以解决问题:

itemslice := reflect.SliceOf(itemtyp)
rv := reflect.New(itemslice)

//现在尝试对json.RawMessage字段进行解组时会出现异常
err = json.Unmarshal(command.Items, rv.Interface())
英文:

You need to pass interface{} to the unmarhsal function, not a reflect.Value.

Changing the following seems to work:

itemslice := reflect.SliceOf(itemtyp)
rv := reflect.New(itemslice)

//now when trying to unmarshal the json.RawMessage field i get an exception
err = json.Unmarshal(command.Items, rv.Interface())

huangapple
  • 本文由 发表于 2014年7月30日 17:46:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/25033662.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定