我正在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))
}
这给出了输出:
case 1: []int [] <nil> null
case 2: []int [] <nil> []
请注意,case 1
和case 2
会产生完全相同的日志输出,除了最终的json字符串外,第一种情况显示null
,第二种情况显示[]
。
为什么会这样?我想要的是让case 1
显示[]
,因为我朋友的客户端应用程序始终期望一个数组,并且零长度数组不应显示为null。
我在做什么错了?
答案 0 :(得分:6)
reflect.New()
按照documentation的作用:
New返回一个值,该值表示指向指定类型的新零值的指针。也就是说,返回的值的类型为PtrTo(typ)。
基本上,它将创建新数据,其值是该类型的零值。 []int
的零值为nil
。
在您的代码中,s0
和s2
都不为零。但是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)
要制作新的切片,请使用reflect.MakeSlice()
。
func makeslice(slice interface{}) interface{} {
return reflect.MakeSlice(reflect.TypeOf(slice), 0, 0).Interface()
}
然后根据您的代码,输出将是:
case 1: []int [] <nil> []
case 2: []int [] <nil> []
工作场所:https://play.golang.org/p/tL3kFqVwOtC
将具有[]int
值的nil
转换为JSON将得到null
。但是将[]int{}
数据转换为JSON将产生[]
,因为数据是空片(而不是nil片)。
作为评论的后续内容,此方法会生成可寻址的切片,可以通过反射进一步修改:
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()
}
更多说明在这里 Why golang reflect.MakeSlice returns un-addressable Value。