# #go #interface
Вопрос:
Я искал решение этой проблемы и не мог найти его здесь, на SO. Я не уверен, что это возможно, но об этом стоит спросить.
У меня есть интерфейс, и мое приложение считывает данные JSON с сервера. Есть несколько типов, которые могут вернуться в ответ, поэтому я использую interface{}
их для использования.
После того , как я разделил байты json на an interface{}
, как я могу преобразовать их в конкретный тип? Если это не удастся, я хотел бы проверить следующий тип для разговора, пока у меня не будет успешного разговора.
Это выглядит примерно так (для краткости удален некоторый код)
type Fooer interface {
Foo()
}
type A struct { }
func (a *A) Foo() { .. }
type B struct { }
func (b *B) Foo() { .. }
// resp is io.ReadCloser
func heavvyWork(resp) {
var parsedResp interface{}
bytesData, err := ioutil.ReadAll(resp)
json.Unmarshal(bytesData, parsedResp)
// convert parsedResp to a concrete type, it might be A or B struct
// try A, if fails, try B.
...
concreteType.Foo()
}
Я просмотрел утверждения типа и приведение, но не смог заставить это работать.
Возможно ли это с Go?
Пример содержимого ответа JSON
A:
{
"data": {
"access_key": "AKIA...",
"secret_key": "xlCs...",
}
}
B:
{
"data": {
"data": {
"foo": "bar"
},
"metadata": {
...
}
}
}
Комментарии:
1. «как я могу преобразовать его в конкретный тип?» — Вручную. Поскольку вы используете
interface{}
в качестве пункта назначения unmarshal, результатом будетmap[string]interface{}
или[]interface{}
или какой-то примитив. Итак , вы берете своеparsedResp
утверждение типа к одному из возможных типов, а затем к каждому элементу, если он у него есть, и так далее… а затем из того, что вы собираете, вы строите конкретные типы. Или просто не используйтеinterface{}
в первую очередь.2. Какая структура?
interface{}
это не структура, выполнениеjson.Unmarshal(data, amp;dest)
там, где dest имеет типinterface{}
без инициализированного динамического типа , волшебным образом не выяснит, что вам нужноA
илиB
. т. е. в нем нет структурыparseResp
.3. Если вы не разберетесь, и
interface{}
вы получитеmap[string]interface{}
объекты JSON. Вам нужно выполнить преобразование из этого или непосредственно из него в нужный конкретный тип.4. @Чена. да, если
data
это так случайно, как вы показываете, и у вас нет возможности заранее узнать, какой конкретный тип представляют байты json, тогда вам придется сделать уродливую вещь, с которой вы возитесьmap[string]interface{}
.5. Смотрите это видео для получения некоторых советов по удалению неизвестных типов.
Ответ №1:
У тебя есть варианты. Ни один из них не является совершенно замечательным.
Один из них, как уже упоминалось, состоит в том, чтобы просто заглянуть внутрь карты в поисках ключей. Я привел пример этого здесь. Это должно быть поучительно, но не особенно эффективно или что-то в этом роде.
Другой способ json.RawMessage
-немного отложить синтаксический анализ. Я привел пример этого здесь. Обратите внимание, как я прибегаю к элементам указателей различных struct
s в декодере. Это раздражает: вы можете захотеть использовать типы данных с указателями только для декодирования и использовать типы без указателей, как только вы выбрали тип. Но это позволяет вам использовать больше пакетов json напрямую (через теги структуры).
Еще один способ-использовать json.NewDecoder
для получения потокового декодера и работы с ним. Это, вероятно, был бы самый надежный метод, но и самый сложный.
Комментарии:
1. Спасибо за подробные примеры. Я подумываю о том, чтобы его реорганизовать. Создайте универсальную структуру для анализа json (как в вашем 2-м примере), а затем выясните, какая это структура, на основе ожидаемого содержимого. У вас есть пример этого
json.NewDecoder
?2. Нет, новый декодер выглядел самым сложным из всех, и я просто остановился на этом. 🙂