由reflect.New()生成的切片的JSON编组在golang中给出null

Joh*_*ohn 3 json go reflect

我在golang中使用reflect来创建一个新的初始化切片.但是当我json.Marshal这个新的反射切片时,我得到一个JSON null值而不是一个[].在这里看到这个例子,我比较两种情况:

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))

}
Run Code Online (Sandbox Code Playgroud)

这给出了输出:

case 1: []int [] <nil> null
case 2: []int [] <nil> []
Run Code Online (Sandbox Code Playgroud)

请注意case 1case 2生成完全相同的日志输出,但最终的json字符串除外,第一个案例显示null,第二个案例显示[].

为什么会这样?我想要的是case 1显示,[]因为我朋友的客户端应用程序总是期望一个数组,并且零长度数组不应该显示为null.

我究竟做错了什么?

nov*_*ung 6

reflect.New()根据文件做什么:

New返回一个Value,表示指向指定类型的新零值的指针.也就是说,返回的Value的类型是PtrTo(typ).

基本上它会创建具有值的新数据是该类型的零值.零值[]intnil.

在你的代码,都s0s2不为零.但是s1它将是类型的零值[]int(即nil),因为它是使用创建的reflect.New().

下面的代码是切片零值的证明nil.

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

var b []int
log.Printf("%#v \n", b) // ====> []int(nil)
Run Code Online (Sandbox Code Playgroud)

所以要制作新切片,请使用reflect.MakeSlice().

func makeslice(slice interface{}) interface{} {
    return reflect.MakeSlice(reflect.TypeOf(slice), 0, 0).Interface()
}
Run Code Online (Sandbox Code Playgroud)

然后根据您的代码输出将是:

case 1: []int [] <nil> []
case 2: []int [] <nil> []
Run Code Online (Sandbox Code Playgroud)

工作场所:https://play.golang.org/p/tL3kFqVwOtC


转换nil[]int价值成JSON将导致nil.但是null会导致将数据转换为JSON,[]int{}因为数据是空切片(不是零切片).


作为注释的后续,此方法生成一个可寻址切片,可以使用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()
}
Run Code Online (Sandbox Code Playgroud)

更多解释 为什么golang reflect.MakeSlice返回不可寻址的值.