JSON маршал среза, сделанного из рефлекса.New() дает нулевое значение в golang
Я использую рефлекс в golang, чтобы сделать новый инициализированный фрагмент. Но в тот момент, когда я 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
показывать []
вместо этого, потому что клиентское приложение моего друга всегда ожидает массив, и массив нулевой длины не должен отображаться как ноль.
Что я делаю неправильно?
1 ответ
Какие reflect.New()
делает согласно документации:
New возвращает значение, представляющее указатель на новое нулевое значение для указанного типа. То есть тип возвращаемого значения - PtrTo(тип).
В основном это создаст новые данные со значением, равным нулевому значению типа. Нулевое значение []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 приведут []
потому что данные пустой срез (не ноль срез).
В качестве последующего комментария этот метод создает адресуемый фрагмент, который может быть дополнительно изменен с помощью отражение:
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()
}
Более подробное объяснение здесь Почему golang отражают. MakeSlice возвращает не адресуемое значение.