Подтвердить что ты не робот

JSON и работа с невыполненными полями

Есть ли какая-то техническая причина, по которой некортированные поля не включаются в кодировку /json? Если это не так, и это произвольное решение, возможно, есть дополнительный вариант задней двери (например, "+" ), чтобы включить хотя бы не экспортированный?

Требуется, чтобы клиентский код для экспорта, чтобы получить эту функциональность, чувствует себя неудачно, особенно если в нижнем регистре содержится инкапсуляция или решение для маршальных структур приходит гораздо позже, чем их дизайн.

Как люди справляются с этим? Просто экспортируйте все?

Кроме того, не экспортирует имена полей, что затрудняет выполнение предложенных идиом. Я думаю, что если структура X имеет поле Y, у вас не может быть метода доступа Y(). Если вы хотите предоставить доступ к интерфейсу Y, вам нужно придумать новое имя для получателя, и независимо от того, что вы получите что-то не-идиоматическое в соответствии с http://golang.org/doc/effective_go.html#Getters

4b9b3361

Ответ 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, для поплавка, что приводит к потере точности. (весь код не проверен)