dongyuli4538
2018-11-01 07:41
浏览 156

由reflect.New()制成的切片的JSON元帅在golang中给出null

I'm using reflect in golang to make a new initialized slice. But the moment I json.Marshal this new reflected slice, I get a JSON null value instead of a []. See this example here where I compare two cases:

package main

import (
  "encoding/json"
  "reflect"
  "log"
)
func makeslice(slice interface{}) interface{} {

  return reflect.New(reflect.TypeOf(slice)).Elem().Interface()
}
func main() {

  s0 := []int{2,3,5}

  s1 := makeslice(s0).([]int)
  js1,e1 := json.Marshal(s1)
  log.Println("case 1:",reflect.TypeOf(s1),reflect.ValueOf(s1),e1,string(js1))

  s2 := []int{}
  js2,e2 := json.Marshal(s2)
  log.Println("case 2:",reflect.TypeOf(s2),reflect.ValueOf(s2),e2,string(js2))

}

This gives output of:

case 1: []int [] <nil> null
case 2: []int [] <nil> []

Notice that case 1 and case 2 produce exactly the same log output except for the final json string, where the first case shows null and the second case shows [].

Why is this the case? What I want is for case 1 to show [] instead because my friend's client side application is always expecting an array, and a zero length array should not be shown as a null.

What am I doing wrong?

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • donglaoping9702 2018-11-01 07:58
    已采纳

    What reflect.New() does as per documentation:

    New returns a Value representing a pointer to a new zero value for the specified type. That is, the returned Value's Type is PtrTo(typ).

    Basically it'll create new data with value is the zero value of the type. The zero value of []int is nil.

    In your code, both s0 and s2 are not nil. But s1 will be zero value of the []int type (which is nil), since it's created using reflect.New().

    Code below is a proof that slice zero value is nil.

    var a []int = []int{}
    log.Printf("%#v 
    ", a) // ====> []int{}
    
    var b []int
    log.Printf("%#v 
    ", b) // ====> []int(nil)
    

    I suggest to use reflect.MakeSlice() instead for making a slice. The generated value won't be a nil.

    func makeslice(slice interface{}) interface{} {
        return reflect.MakeSlice(reflect.TypeOf(slice), 0, 0).Interface()
    }
    

    Then based on your code the output would be:

    case 1: []int [] <nil> []
    case 2: []int [] <nil> []
    

    Working playground: https://play.golang.org/p/tL3kFqVwOtC


    Converting []int with nil value into JSON will result null. But converting []int{} data into JSON will result [] because the data is empty slice (not a nil slice).


    As followup to comment, this method produces an addressable slice that can be modified further with reflect:

    func makeslice(slice interface{}) interface{} {
        newsliceval := reflect.MakeSlice(reflect.TypeOf(slice),0,0)
        newslice := reflect.New(newsliceval.Type()).Elem()
        newslice.Set(newsliceval)
    
        /*
         * make any desired changes to newslice with reflect package
         */
    
        return newslice.Interface()
    }
    

    More explanation here Why golang reflect.MakeSlice returns un-addressable Value.

    打赏 评论