对象在网络中是通过字节数组来进行传递的,在日常的前后端交互中,有可能会用到会有多种的形式,比如json,xml,pb等。这篇文章主要介绍一下golang语言中json相关库的日常用法
序列化是指把内存中的对象转为字节数组的过程,方便在网络中传输,反序列化则相反,golang中涉及到的两个函数,包的位置:“encoding/json”
package json
// 序列化
func Marshal(v interface{}) ([]byte, error) {
}
// 反序列化
func Unmarshal(data []byte, v interface{}) error {
}
序列化传入对象,返回字节数组
反序列化传入字节数组和接收对象的地址,会自动填充对象
看一个例子:
type Student struct {
Name string
Age uint32
}
func main() {
stu := Student{
Name: "james",
Age: 22,
}
// marshal
jsonObj, err := json.Marshal(stu)
if err != nil {
panic(err)
}
fmt.Printf("jsonObj : %s", jsonObj)
str := `{"Name":"james","Age":22}`
var stu2 Student
// unmarshal
err = json.Unmarshal([]byte(str), &stu2)
if err != nil {
panic(err)
}
fmt.Printf("stu2 : %+v\n", stu2)
}
运行结果:
注意: 这里有一个坑,golang的字段名必须大写开头,否则无法完成json的序列化,会丢失该字段。如果这里我们把Name小写,则无法完成映射
// 错误的写法,字段必须大写,保持为public
type Student struct {
name string
age uint32
}
通过上述的例子可以看到序列化后的字段名和golang的字段名是一样的,是大写的Name,有时前后端约定的json对象字段名并不相同,就需要通过tag完成映射
type Student struct {
Name string `json:"name"`
Age uint32 `json:"age"`
}
使用该tag后,序列化时,当某个字段没有值(在golang中也就是为0值)时,会直接忽略该字段
看下区别,很容易理解:
为Age添加omitempty字段
type Student struct {
Name string `json:"name"`
Age uint32 `json:"age,omitempty"`
}
将年龄设置为0值,或者不初始化
stu := Student{
Name: "james",
Age: 0,
}
注意:这里主要取决于协议需求
当用户想要输入的时间为2006-01-02 15:04:05这种格式时,直接使用time.Time类型进行接收会遇到一个问题:cannot parse " 00:00:00"" as “T”
type XXXConfig struct {
StartDate time.Time `json:"start_date"`
EndDate time.Time `json:"end_date"`
}
因为golang的底层时间类型不一样导致的,需要重新定义别名,然后修改接口实现
const (
YYYYMMDD = "2006-01-02"
DefaultTimeFormat = "2006-01-02 15:04:05"
)
// JSONTime is time
type JSONTime time.Time
// UnmarshalJSON for JSON Time
func (t *JSONTime) UnmarshalJSON(data []byte) (err error) {
now, err := time.ParseInLocation(`"`+DefaultTimeFormat+`"`, string(data), time.Local)
*t = JSONTime(now)
return
}
// MarshalJSON for JSON Time
func (t JSONTime) MarshalJSON() ([]byte, error) {
b := make([]byte, 0, len(DefaultTimeFormat)+2)
b = append(b, '"')
b = time.Time(t).AppendFormat(b, DefaultTimeFormat)
b = append(b, '"')
return b, nil
}
// String for JSON Time
func (t JSONTime) String() string {
return time.Time(t).Format(DefaultTimeFormat)
}
这时,将结构体字段类型改变下为自己的定义的类型就解决了
type XXXConfig struct {
StartDate JSONTime `json:"start_date"`
EndDate JSONTime `json:"end_date"`
}