JSON e lidando com campos não exportados

Existe uma razão técnica pela qual os campos não exportados não são incluídos pela codificação / json? Se não, e é uma decisão arbitrária, pode haver uma opção adicional de porta traseira (digamos ‘+’) para include, mesmo que não seja exportada?

Exigir que o código do cliente para exportar para obter essa funcionalidade pareça lamentável, especialmente se as letras minúsculas estiverem fornecendo encapsulamento ou a decisão de organizar as estruturas for muito posterior ao design delas.

Como as pessoas estão lidando com isso? Apenas exportar tudo?

Além disso, não exportar nomes de campos dificulta seguir as expressões sugeridas. Eu acho que se uma struct X tem campo Y, você não pode ter um método de acessador Y (). Se você quiser fornecer access à interface para Y, você precisa criar um novo nome para o getter e não importa o que você obterá de algo não-idiomático, de acordo com http://golang.org/doc/effective_go.html#Getters

Existe uma razão técnica. A biblioteca json não tem o poder de exibir campos usando reflect, a menos que eles sejam exportados. Um pacote só pode exibir os campos não exportados de tipos dentro de seu próprio pacote

Para lidar com seu problema, o que você pode fazer é criar um tipo não exportado com campos exportados. Json irá unmarshal em um tipo não exportado se passado a ele sem um problema, mas não apareceria nos documentos da API. Você pode então fazer um tipo exportado que incorpora o tipo não exportado. Esse tipo exportado precisaria, então, de methods para implementar as interfaces json.Unmarshaler e json.Unmarshaler .

Nota: todo o código não foi testado e pode nem ser compilado.

 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 } 

A resposta de Stephen está completa. Como um aparte, se tudo o que você realmente quer são chaves minúsculas no seu json, você pode especificar manualmente o nome da chave da seguinte forma:

 type Whatever struct { SomeField int `json:"some_field"` } 

Dessa forma, marshaling a Whatever produz a chave “some_field” para o campo SomeField (em vez de ter “SomeField” no seu json).

Se você está pronto para guardar campos não exportados, você também pode implementar a interface json.Marshaler definindo um método com a assinatura MarshalJSON() ([]byte, error) . Uma maneira de fazer isso é usar um literal de estrutura que simplesmente exportou versões dos campos não exportados, como este:

 type Whatever struct { someField int } func (w Whatever) MarshalJSON() ([]byte, error) { return json.Marshal(struct{ SomeField int `json:"some_field"` }{ SomeField: w.someField, }) } 

Isso pode ser um pouco complicado, então você também pode usar uma map[string]interface{} se preferir:

 func (w Whatever) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]interface{}{ "some_field": w.SomeField, }) } 

No entanto, deve-se notar que a interface{} empacotamento interface{} tem algumas ressalvas e pode fazer coisas como empacotar o uint64 em um ponto flutuante, causando uma perda de precisão. (todo código não testado)