我在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 1并case 2生成完全相同的日志输出,但最终的json字符串除外,第一个案例显示null,第二个案例显示[].
为什么会这样?我想要的是case 1显示,[]因为我朋友的客户端应用程序总是期望一个数组,并且零长度数组不应该显示为null.
我究竟做错了什么?
reflect.New()根据文件做什么:
New返回一个Value,表示指向指定类型的新零值的指针.也就是说,返回的Value的类型是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)
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返回不可寻址的值.
| 归档时间: |
|
| 查看次数: |
373 次 |
| 最近记录: |