dongyuli4538 2018-11-01 07:41
浏览 171
已采纳

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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥30 BC260Y用MQTT向阿里云发布主题消息一直错误
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退