Я реализую некоторые методы для сериализации объектов (которые, вероятно, уже существуют в стандартной библиотеке, но я хочу опыт).
Мне удалось заставить json.Marshal и json.Unmarshal правильно преобразовать мои данные в строку и затем прочитать обратно в объект, но я заметил интересное поведение, которое я хочу лучше понять.
Чтобы проверить функции пакета json, я создал тестовую структуру:
type Test struct{
T int
S string
F float32
}
Запуск
o := Test{32, "struct", 12.07}
b, e := json.Marshal(o)
fmt.Println(string(b), e)
печать
{"T":32,"S":"struct","F":12.07} <nil>
что я и ожидал. Тем не менее, я могу получить два разных результата при демаршаллинге, в зависимости от того, когда я конвертирую объект в указатель:
// Test 1
var o2 interface{} = &o
e = json.Unmarshal(b, o2)
fmt.Println(o2, e)
печать
// Output 1
&{32 struct 12.07} <nil>
при определении o2 как значения, а не указателя, а затем вызове Unmarshal с & o2, т.е..
// Test 2
var o2 interface{} = o
e = json.Unmarshal(b, &o2)
fmt.Println(o2, e)
печать
// Output 2
map[T:32 S:struct F:12.07] <nil>
Интересно, что все четыре из
// Test 3
var o2 Test = o
e = json.Unmarshal(b, &o2)
fmt.Println(o2, e)
// Test 4
var o2 *Test = &o
e = json.Unmarshal(b, &o2)
fmt.Println(*o2, e)
// Test 5
var o2 *Test = &o
e = json.Unmarshal(b, o2)
fmt.Println(o2, e)
и
// Test 6
var o2 *Test = &o
e = json.Unmarshal(b, &o2)
fmt.Println(o2, e)
выведите одно из следующих значений:
// Output 3, 4
{32 struct 12.07} <nil>
// Output 5, 6
&{32 struct 12.07} <nil>
Тесты 1 и 2 наводят меня на мысль, что некоторая информация времени выполнения теряется, когда что-то присваивается «суперклассу» ... кажется, что присвоение указателя на мою структуру для o2 дает функции Unmarshal больше данных о типе должен прочитать, чем присвоить мою структуру o2, а затем передать указатель на o2 Unmarshal. Это имеет немного смысла; во время компиляции Тест 1 передает интерфейс {} Unmarshal, в то время как Тест 2 передает указатель на интерфейс {}. Тем не менее, я бы подумал, что тип аргумента во время выполнения был бы таким же (* Test). Может кто-нибудь объяснить, почему Go работает таким образом?
Подтверждением моего вывода является тот факт, что объявление o2 в качестве теста или * теста позволяет Unmarshal (который таким образом получает * Test в качестве аргумента) всегда читать мои данные как структуру, а не как карту.
Странно, но Тест 4 и Тест 6 показывают, что передача указателя на указатель на мою структуру полностью приемлема, и Unmarshal правильно (?) Устанавливает значение структуры. Я ожидал бы ошибку времени выполнения для этих тестов, поскольку Unmarshal должен был попытаться разыменовать двойной указатель и установить результирующий указатель на сериализованную структуру, которую он читал. Автоматическая разыменование с несколькими указателями может быть просто функцией этой функции, но это не было упомянуто в официальной документации. Я не слишком обеспокоен этими последними тестами. Меня больше всего интересует, что будет причиной различий между Тестом 1 и Тестом 2.
** Отредактировано 14 января 2018 года, чтобы изменить второй json.Marshal на json. Удалите неправильные скобки из кода копирования / вставки