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 возвращает не адресуемое значение.

Другие вопросы по тегам