英文:
Specify struct format in json.Marshal()
问题
我有以下的结构体,用于与一个API进行通信:
type Object struct {
Id uint64
Type string
Class string
Properties []Property
}
type Property struct {
Name string
DataType string
Value interface{}
}
在发送之前,我使用json.MarshalIndent()
将结构体转换为JSON,得到的结果如下:
{
"Id": 15,
"Type": "Node",
"Class": "Persona",
"Properties": [
{
"Name": "Nombre",
"DataType": "text",
"Value": "Oso"
},
{
"Name": "Edad",
"DataType": "int",
"Value": 45
},
{
"Name": "Fecha de Naciemiento",
"DataType": "date",
"Value": "1989-09-27T05:30:08-06:00"
}
]
}
我想在进行编组之前格式化Value
的值(因为它是interface{}
类型,所以需要根据值的类型进行格式化)。
我想到的第一个解决方案是创建一个(Object) encode() string
函数或类似的函数,遍历[]Property
并格式化值,然后分别对每个属性进行编组,然后使用[]string
重建Object,然后对对象进行编组。
是否有内置的方法可以实现这个?如果没有,是否有惯用的方法可以实现这个?
英文:
I have the following structs, which I use to communicate with an API:
type Object struct {
Id uint64
Type string
Class string
Properties []Property
}
type Property struct {
Name string
DataType string
Value interface{}
}
And I use json.MarshalIndent()
to convert my struct into a json before sending it. this gives me something like:
{
"Id": 15,
"Type": "Node",
"Class": "Persona",
"Properties": [
{
"Name": "Nombre",
"DataType": "text",
"Value": "Oso"
},
{
"Name": "Edad",
"DataType": "int",
"Value": 45
},
{
"Name": "Fecha de Naciemiento",
"DataType": "date",
"Value": "1989-09-27T05:30:08-06:00"
}
]
}
I want to format the value
value (because it is of type interface{}
I need to format it depending on the value type) of the struct Property before marshaling it.
The first solution that occurred to me was to create a (Object) encode() string
function or something, that iterates through []Property
formatting the values, and marshaling each property separately, then reconstructing the Object with an []string
instead of the []Property
and then marshaling the object.
Is there any built-in way of doing this? If not, is there any idiomatic way of doing it?
答案1
得分: 1
JSON编码器根据值的实际类型对interface{}值进行编码。你可以通过几种方式来覆盖默认的编码方式。
第一种方式是创建一个包装器来控制值的编码方式,使用Marshaler接口。下面是一个改变整数编码方式的包装器示例:
type Value struct{ Value interface{} }
func (v Value) MarshalJSON() ([]byte, error) {
switch v := v.Value.(type) {
case int:
return []byte(fmt.Sprintf("\"#%d\"", v)), nil
default:
return json.Marshal(v)
}
}
使用方法如下:
prop.Value = Value{45}
第二种方式是在Property类型上实现Marshaler,以覆盖整个属性(包括Value字段)的编码方式。
func (p Property) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
buf.WriteString(`{"Name":`)
d, err := json.Marshal(p.Name)
if err != nil {
return nil, err
}
buf.Write(d)
buf.WriteString(`,"DataType":`)
d, err = json.Marshal(p.DataType)
if err != nil {
return nil, err
}
buf.Write(d)
buf.WriteString(`, "Value":`)
switch v := p.Value.(type) {
case int:
fmt.Fprintf(&buf, "\"#%d\"", v)
default:
d, err := json.Marshal(v)
if err != nil {
return nil, err
}
buf.Write(d)
}
buf.WriteString("}")
return buf.Bytes(), nil
}
英文:
The JSON encoder marshals interface{} values according to the actual type of the value. You can override the default encoding in a couple of ways.
The first is to create a wrapper around values to control how they are encoded using the Marshaler interface. Here's a wrapper that changes how integers are encoded:
type Value struct{ Value interface{} }
func (v Value) MarshalJSON() ([]byte, error) {
switch v := v.Value.(type) {
case int:
return []byte(fmt.Sprintf("\"#%d\"", v)), nil
default:
return json.Marshal(v)
}
}
Use it like this:
prop.Value = Value{45}
<kbd>playground</kbd>
A second approach is to implement the Marshaler on the Property type to override how all of the property is marshaled including the Value field.
func (p Property) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
buf.WriteString(`{"Name":`)
d, err := json.Marshal(p.Name)
if err != nil {
return nil, err
}
buf.Write(d)
buf.WriteString(`,"DataType":`)
d, err = json.Marshal(p.DataType)
if err != nil {
return nil, err
}
buf.Write(d)
buf.WriteString(`, "Value":`)
switch v := p.Value.(type) {
case int:
fmt.Fprintf(&buf, "\"#%d\"", v)
default:
d, err := json.Marshal(v)
if err != nil {
return nil, err
}
buf.Write(d)
}
buf.WriteString("}")
return buf.Bytes(), nil
}
<kbd>playground</kbd>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论