JSON маршал среза, сделанного из рефлекса. New () дает нулевое значение в golang - PullRequest
0 голосов
/ 01 ноября 2018

Я использую отражение в golang, чтобы создать новый инициализированный фрагмент. Но в тот момент, когда я создаю этот новый отраженный фрагмент, я получаю значение 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 Ответ

0 голосов
/ 01 ноября 2018

Что 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() вместо того, чтобы сделать ломтик. Сгенерированное значение не будет 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


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

...