JSON 由 reflect.New() 制作的切片元帅在 golang 中给出 null
JSON marshal of slice made from reflect.New() gives null in golang
我在 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。
我做错了什么?
reflect.New()
按照 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).
在您的代码中,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()
来代替切片。生成的值不会是 nil
.
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
将值 nil
的 []int
转换为 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.
我在 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。
我做错了什么?
reflect.New()
按照 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).
在您的代码中,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()
来代替切片。生成的值不会是 nil
.
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
将值 nil
的 []int
转换为 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.