func Marshal(v interface{}) ([]byte, error) // 生成 JSON
func Unmarshal(data []byte, v interface{}) error // 解析 JSON 到 struct
1.1.1 已知JSON结构
先看例子
package main
import (
“encoding/json”
“fmt”
)
type Person struct {
Name string
Age string
}
type PersonSlice struct {
Persons []Person
}
func main() {
var s PersonSlice
str := {"persons":[{"Name":"FanOne","Age":"17"},{"Name":"FanOne2","Age":"18"},{"Name":"FanOne3","Age":"19"}]}
_ = json.Unmarshal([]byte(str), &s)
// Golang中提供软件包"encoding/json"可以直接用来处理JSON文件,此包中解析JSON的函数为Unmarshal
// 使用此函数可以将JSON文件解析到结构体中
fmt.Println(s.Persons)//[{FanOne 17} {FanOne2 18} {FanOne3 19}]
for _,item:=range s.Persons{
fmt.Println(“Name”,item.Name,“Age”,item.Age)
//Name FanOne Age 17
//Name FanOne2 Age 18
//Name FanOne3 Age 19
}
}
上例中,首先定义了与json数据对应的结构体,数组对应slice,字段名对应JSON里面的KEY,
在解析的时候,如何将json数据与struct字段相匹配呢?例如JSON的key是Name,那么怎么找对应的字段呢?
- 首先查找tag含有Name的可导出的struct字段(首字母大写)
- 其次查找字段名是Name的导出字段
- 最后查找类似NAME或者NaMe这样的除了首字母之外其他大小写不敏感的导出字段
其中需要注意一点:能够被赋值的字段必须是可导出字段(即首字母大写
)。因为只有首字母大写
才能被外面应用,同时JSON解析的时候只会解析能找得到的字段,找不到的字段会被忽略。
这样的一个好处是:当你接收到一个很大的JSON数据结构而你却只想获取其中的部分数据的时候,你只需将你想要的数据对应的字段名大写,即可轻松解决这个问题。
虽然没有python直接.json那么方便,但是也还是算不错的。
1.1.2 未知JSON结构
众所周知,在Go语言中,interface{}
可以用来存储任意数据类型的对象,此数据结构正好用于存储解析的未知结构的json数据的结果。
JSON包中采用map[string]interface{}
和[]interface{}
结构来存储任意的JSON对象
和数组
。
Go类型和JSON类型的对应关系如下:
- bool 代表 JSON booleans,
- float64 代表 JSON numbers,
- string 代表 JSON strings,
- nil 代表 JSON null.
b := []byte({ "Name": "FanOne", "School": ["FZU", "XCZX", "UUUU", "GuaguaSong", "HanTuo", "City", "FuZhou"], "Major": "BigData", "IsPublished": true, "Price": 9.99, "Sales": 1000000 }
)
var r interface{}
err := json.Unmarshal(b, &r)
在上述代码中,r 被定义为一个空接口。
json.Unmarshal()
函数将一个 JSON 对象解码
到空接口 r 中,最终 r 将会是一个键值对的map[string]interface{}
结构:
map[string]interface{}{
“Name”: “FanOne”,
“School”: [“FZU”, “XCZX”, “UUUU”, “GuaguaSong”, “HanTuo”,
“City”, “FuZhou”],
“Major”: “BigData”,
“IsPublished”: true,
“Price”: 9.99,
“Sales”: 1000000
}
要访问解码后的数据结构,需要先判断目标结构是否为预期的数据类型:
gobook, ok := r.(map[string]interface{})
然后,我们可以通过 for 循环搭配 range 语句一一访问解码后的目标数据:
if ok {
for k, v := range gobook
{
switch v2 := v.(type)
{
case string:
fmt.Println(k, “is string”, v2)
case int:
fmt.Println(k, “is int”, v2)
case bool:
fmt.Println(k, “is bool”, v2)
case []interface{}:
fmt.Println(k, “is an array:”)
for i, iv := range v2 {
fmt.Println(i, iv)
}
default:
fmt.Println(k, “is another type not handle yet”)
}
}
}
虽然有些烦琐,但的确是一种解码未知结构的 JSON 数据的安全方式。
1.1.3 Encoder & Decoder
Go 内建的 encoding/json 包还提供 Decoder 和 Encoder 两个类型,用于支持 JSON 数据的流式读写,并提供 NewDecoder()和 NewEncoder()两个函数来便于具体实现:
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
func main() {
dec := json.NewDecoder(os.Stdin)
enc := json.NewEncoder(os.Stdout)
for {
var v map[string]interface{}
if err := dec.Decode(&v); err != nil{
log.Println(err)
return
}
for k := range v {
if k != “Name” {
v[k] = nil,false
}
}
if err := enc.Encode(&v); err != nil{
log.Println(err)
}
}
}
使用 Decoder 和 Encoder 对数据流进行处理可以应用得更为广泛些,比如读写 HTTP 连接、WebSocket 或文件等,Go 的标准库 net/rpc/jsonrpc 就是一个应用了 Decoder 和 Encoder的实际例子。
1.2 XML文件
XML 数据格式
对于如下的XML:
和 JSON 的方式一样,XML 数据可以序列化为结构,或者从结构反序列化为 XML 数据;
encoding/xml
包实现了一个简单的 XML 解析器(SAX),用来解析 XML 数据内容。下面的例子说明如何使用解析器:
复制代码
// xml.go
package main
import (
“encoding/xml”
“fmt”
“strings”
)
var t, token xml.Token
var err error
func main() {
input := “FanOne”
inputReader := strings.NewReader(input)
p := xml.NewDecoder(inputReader)
for t, err = p.Token(); err == nil; t, err = p.Token() {
switch token := t.(type) {
case xml.StartElement:
name := token.Name.Local
fmt.Printf(“Token name: %s\n”, name)
for _, attr := range token.Attr {
attrName := attr.Name.Local
attrValue := attr.Value
fmt.Printf(“An attribute is: %s %s\n”, attrName, attrValue)
}
case xml.EndElement:
fmt.Println(“End of token”)
case xml.CharData:
content := string([]byte(token))
fmt.Printf(“This is the content: %v\n”, content)
// …
default:
// …
}
}
}
输出:
Token name: Person
Token name: FirstName
This is the content: Fan
End of token
Token name: LastName
This is the content: One
End of token
End of token
包中定义了若干XML
标签类型:StartElement,Chardata(这是从开始标签到结束标签之间的实际文本)EndElement,Comment,Directive 或 ProcInst。
包中同样定义了一个结构解析器:
NewParser
方法持有一个 io.Reader
(这里具体类型是strings.NewReader
)并生成一个解析器类型的对象。
还有一个 Token()
方法返回输入流里的下一个 XML token
。在输入流的结尾处,会返回(nil,io.EOF)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!**
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-vdWZxEt5-1713001746272)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!