go 导入json包

读者可能注意到了,导入json包的时候需要指定encoding路径。不考虑这个路径的话,我们导入包的名字叫作json。不管标准库的路径是什么样的,并不会改变包名。我们在访问json 包内的函数时,依旧是指定json这个名字。
在第 08 行,我们声明了一个叫作dataFile的常量,使用内容是磁盘上根据相对路径指定的数据文件名的字符串做初始化。因为 Go 编译器可以根据赋值运算符右边的值来推导类型,声明常量的时候不需要指定类型。此外,这个常量的名称使用小写字母开头,表示它只能在search 包内的代码里直接访问,而不暴露到包外面。
接着我们来看看data.json数据文件的部分内容,如代码清单 2-27 所示。
代码清单 2-27 data.json
[
{
“site” : “npr”,
“link” : “http://www.npr.org/rss/rss.php?id=1001”,
“type” : “rss”
},
{
“site” : “cnn”,
“link” : “http://rss.cnn.com/rss/cnn_world.rss”,
“type” : “rss”
},
{
“site” : “foxnews”,
“link” : “http://feeds.foxnews.com/foxnews/world?format=xml”, “type” : “rss”
},
{
“site” : “nbcnews”,
“link” : “http://feeds.nbcnews.com/feeds/topstories”, “type” : “rss”
}
]
为了保证数据的有效性,代码清单 2-27 只选用了 4 个数据源,实际数据文件包含的数据要比这 4 个多。数据文件包括一个 JSON 文档数组。数组的每一项都是一个 JSON 文档,包含获取数据的网站名、数据的链接以及我们期望获得的数据类型。这些数据文档需要解码到一个结构组成的切片里,以便我们能在程序里使用这些数据。来看
看用于解码数据文档的结构类型,如代码清单 2-28 所示。
代码清单 2-28 feed.go:第 10 行到第 15 行
10 // Feed 包含我们需要处理的数据源的信息
11 type Feed struct {
12 Name string json:"site"
13 URI string json:"link"
14 Type string json:"type"
15 }
在第 11 行到第 15 行,我们声明了一个名叫Feed的结构类型。这个类型会对外暴露。这个
类型里面声明了 3 个字段,每个字段的类型都是字符串,对应于数据文件中各个文档的不同字段。每个字段的声明最后 ` 引号里的部分被称作标记(tag)。这个标记里描述了 JSON 解码的元数据,用于创建Feed类型值的切片。每个标记将结构类型里字段对应到 JSON 文档里指定名字的字段。现在可以看看 search.go 代码文件的第 14 行中调用的RetrieveFeeds函数了。这个函数读
取数据文件,并将每个 JSON 文档解码,存入一个Feed类型值的切片里,如代码清单 2-29 所示。
代码清单 2-29 feed.go:第 17 行到第 36 行
17 // RetrieveFeeds读取并反序列化源数据文件
18 func RetrieveFeeds() ([]*Feed, error) {
19 // 打开文件
20 file, err := os.Open(dataFile)
21 if err != nil {
22 return nil, err
23 }
24
25 // 当函数返回时
26 // 关闭文件
27 defer file.Close()
28
29 // 将文件解码到一个切片里
30 // 这个切片的每一项是一个指向一个Feed类型值的指针
31 var feeds []*Feed
32 err = json.NewDecoder(file).Decode(&feeds)
33
34 // 这个函数不需要检查错误,调用者会做这件事
35 return feeds, err
36 }
让我们从第 18 行的函数声明开始。这个函数没有参数,会返回两个值。第一个返回值是一个切片,其中每一项指向一个Feed类型的值。第二个返回值是一个error类型的值,用来表示函数是否调用成功。在这个代码示例里,会经常看到返回error类型值来表示函数是否调用成功。这种用法在标准库里也很常见。
现在让我们看看第 20 行到第 23 行。在这几行里,我们使用os包打开了数据文件。我们使用相对路径调用Open方法,并得到两个返回值。第一个返回值是一个指针,指向File类型的值,第二个返回值是error类型的值,检查Open调用是否成功。紧接着第 21 行就检查了返回的error类型错误值,如果打开文件真的有问题,就把这个错误值返回给调用者。
如果成功打开了文件,会进入到第 27 行。这里使用了关键字defer,如代码清单 2-30 所示。
代码清单 2-30 feed.go:第 25 行到第 27 行
25 // 当函数返回时
26 // 关闭文件
27 defer file.Close()
关键字defer会安排随后的函数调用在函数返回时才执行。在使用完文件后,需要主动关闭文件。使用关键字defer来安排调用Close方法,可以保证这个函数一定会被调用。哪怕函数意外崩溃终止,也能保证关键字defer安排调用的函数会被执行。关键字defer可以缩短打
开文件和关闭文件之间间隔的代码行数,有助提高代码可读性,减少错误。
现在可以看看这个函数的最后几行,如代码清单 2-31 所示。先来看一下第 31 行到第 35 行的代码。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值