JSON и работа с невыполненными полями
Есть ли какая-то техническая причина, по которой некортированные поля не включаются в кодировку /json? Если это не так, и это произвольное решение, возможно, есть дополнительный вариант задней двери (например, "+" ), чтобы включить хотя бы не экспортированный?
Требуется, чтобы клиентский код для экспорта, чтобы получить эту функциональность, чувствует себя неудачно, особенно если в нижнем регистре содержится инкапсуляция или решение для маршальных структур приходит гораздо позже, чем их дизайн.
Как люди справляются с этим? Просто экспортируйте все?
Кроме того, не экспортирует имена полей, что затрудняет выполнение предложенных идиом. Я думаю, что если структура X имеет поле Y, у вас не может быть метода доступа Y(). Если вы хотите предоставить доступ к интерфейсу Y, вам нужно придумать новое имя для получателя, и независимо от того, что вы получите что-то не-идиоматическое в соответствии с http://golang.org/doc/effective_go.html#Getters
Ответы
Ответ 1
Существует техническая причина. Библиотека json не имеет возможности просматривать поля с использованием отражения, если они не экспортируются. Пакет может просматривать только нераспределенные поля типов внутри своего собственного пакета.
Чтобы справиться с вашей проблемой, вы можете сделать неэкспортный тип с экспортированными полями. Json будет отключаться от неэкспортированного типа, если его передать без проблем, но он не будет отображаться в документах API. Затем вы можете сделать экспортированный тип, который введет неэкспортированный тип. Затем этому экспортированному типу нужны методы для реализации интерфейсов json.Marshaler
и json.Unmarshaler
.
Примечание: весь код не проверен и даже не компилируется.
type jsonData struct {
Field1 string
Field2 string
}
type JsonData struct {
jsonData
}
// Implement json.Unmarshaller
func (d *JsonData) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &d.jsonData)
}
// Getter
func (d *JsonData) Field1() string {
return d.jsonData.Field1
}
Ответ 2
Ответ Стивена завершен. В стороне, если все, что вам действительно нужно, это строчные ключи в json, вы можете вручную указать имя ключа следующим образом:
type Whatever struct {
SomeField int `json:"some_field"`
}
Таким образом, маршалинг "Что бы ни создавал ключ" some_field "для поля SomeField (вместо" SomeField "в вашем json).
Если вы настроены на сохранение нераспределенных полей, вы также можете реализовать интерфейс json.Marshaler, указав метод с подписью MarshalJSON() ([]byte, error)
. Один из способов сделать это - использовать строковый литерал, который просто экспортировал версии невыгруженных полей, например:
type Whatever struct {
someField int
}
func (w Whatever) MarshalJSON() ([]byte, error) {
return json.Marshal(struct{
SomeField int `json:"some_field"`
}{
SomeField: w.someField,
})
}
Это может быть немного громоздким, поэтому вы можете также использовать map[string]interface{}
, если хотите:
func (w Whatever) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]interface{}{
"some_field": w.SomeField,
})
}
Однако следует отметить, что маршалинг interface{}
имеет некоторые оговорки и может делать такие вещи, как маршал uint64
, для поплавка, что приводит к потере точности. (весь код не проверен)