在本文中,我将向您展示如何在Go中解析和返回JSON的基础知识,同时还向您提供对该过程的理解。
首先,让我们看一下如何在其他语言中解析JSON,特别是动态类型的,我将以python为例。
##############
RETURNING JSON
##############
import json
# a Python object (dict):
p_dict = {
"name": "John",
"age": 30,
"city": "New York"
}
# convert into JSON:
y = json.dumps(p_dict)
# the result is a JSON string:
print(y)
##############
CONSUMING JSON
##############
import json
# some JSON:
j_str = '{ "name":"John", "age":30, "city":"New York"}'
# parse x:
y = json.loads(j_str)
# the result is a Python dictionary:
print(y["age"])
json.dumps(p_dict)json.loads(j_str)
现在,在像Go这样的静态类型语言中解析像JSON这样的格式会带来一些问题。Go是静态类型的,这意味着程序中每个变量的类型都需要在编译时知道。这意味着您作为程序员必须指定每个变量的类型。其他语言(python)提供某种形式的类型推断,类型系统能够推断出变量的类型。静态类型语言的主要优点是所有类型的检查都可以由编译器完成,因此在很早的阶段就会发现许多琐碎的错误。一个简单的代码示例可能会澄清。
PYTHON
x = 3
GOLANG
var x int = 3
在解析JSON时,任何东西都可以显示在JSON主体中,那么编译器如何知道如何设置内存,因为它不知道类型?
这有两个答案。当你知道你的数据会是什么样子时会得到一个答案,而当你不了解数据时会得到答案。我们将首先介绍第一个选项,因为这是最常见的情况并导致最佳实践。
当JSON中的数据类型已知时,您应该将JSON解析为您定义的结构。任何不适合结构的字段都将被忽略。我们将在返回和使用JSON时探索此选项。
返回JSON假设我们想要返回以下JSON对象。
{
"key1": "value 1",
"key2": "value 2"
}
下面的代码显示了这是如何完成的,让我们来谈谈它。
package main
import (
"encoding/json"
"fmt"
)
type JSONResponse struct {
Value1 string `json:"key1"`
Value2 string `json:"key2"`
}
func main() {
jsonResponse := JSONResponse{
Value1: "Test value 1",
Value2: "Test value 2",
}
fmt.Printf("The struct returned before marshalling\n\n")
fmt.Printf("%+v\n\n\n\n", jsonResponse)
// The MarshalIndent function only serves to pretty print, json.Marshal() is what would normally be used
byteArray, err := json.MarshalIndent(jsonResponse, "", " ")
if err != nil {
fmt.Println(err)
}
fmt.Printf("The JSON response returned when the struct is marshalled\n\n")
fmt.Println(string(byteArray))
}
json: "key1"
请在此处运行代码以查看结果,使用代码也是学习https://play.golang.org/p/gaBMvz21LiA的最佳方式。
嵌套的JSON
现在让我们看一下具有嵌套项的更复杂的JSON对象
{
"key1": "value 1",
"key2": "value 2",
"nested": {
"nestkey1": "nest value 1",
"nestkey2": "nest value 2"
}
}
下面的代码显示了这是如何完成的,让我们来讨论改变了什么。
package main
import (
"encoding/json"
"fmt"
)
type JSONResponse struct {
Value1 string `json:"key1"`
Value2 string `json:"key2"`
Nested Nested `json:"nested"`
}
type Nested struct {
NestValue1 string `json:"nestkey1"`
NestValue2 string `json:"nestkey2"`
}
func main() {
nested := Nested{
NestValue1: "nest value 1",
NestValue2: "nest value 2",
}
jsonResponse := JSONResponse{
Value1: "value 1",
Value2: "value 2",
Nested: nested,
}
// Try uncommenting the section below and commenting out lines 21-30 the result will be the same meaning you can declare inline
// jsonResponse := JSONResponse{
// Value1: "value 1",
// Value2: "value 2",
// Nested: Nested{
// NestValue1: "nest value 1",
// NestValue2: "nest value 2",
// },
// }
fmt.Printf("The struct returned before marshalling\n\n")
fmt.Printf("%+v\n\n\n\n", jsonResponse)
// The MarshalIndent function only serves to pretty print, json.Marshal() is what would normally be used
byteArray, err := json.MarshalIndent(jsonResponse, "", " ")
if err != nil {
fmt.Println(err)
}
fmt.Printf("The JSON response returned when the struct is marshalled\n\n")
fmt.Println(string(byteArray))
}
- 第11行:不是将Nested声明为类型字符串,而是将Nested声明为Nested类型,这是我们即将创建的类型。
- 第14-17行:我们声明了我们在JSONResponse中使用的嵌套类型结构,遵循我们想要返回的JSON的格式。
- 第21-30行:我们实例化Nested类型的嵌套变量和JSONResponse类型的jsonResponse变量,后者又引用我们刚刚声明的嵌套变量。
这些是这个例子和前一个例子之间的主要区别。再次运行此处的代码进行测试,并在评论https://play.golang.org/p/GcRceKe1jC-中进行一些修改。
JSON中的数组
最后,让我们看一下返回包含数组的JSON对象。
{
"key1": "value 1",
"key2": "value 2",
"nested": {
"nestkey1": "nest value 1",
"nestkey2": "nest value 2"
},
"arrayitems": [
{
"iteminfokey1": "item info 1 array index 0",
"iteminfokey2": "item info 2 array index 0"
},
{
"iteminfokey1": "item info 1 array index 1",
"iteminfokey2": "item info 2 array index 1"
}
]
}
下面的代码显示了这是如何完成的,再次让我们讨论一下发生了什么变化。
package main
import (
"encoding/json"
"fmt"
)
type JSONResponse struct {
Value1 string `json:"key1"`
Value2 string `json:"key2"`
Nested Nested `json:"nested"`
ArrayItems []ArrayItem `json:"arrayitems"`
}
type Nested struct {
NestValue1 string `json:"nestkey1"`
NestValue2 string `json:"nestkey2"`
}
type ArrayItem struct {
ItemInfo1 string `json:"iteminfokey1"`
ItemInfo2 string `json:"iteminfokey2"`
}
func main() {
arrayItems := []ArrayItem{
ArrayItem{
ItemInfo1: "item info 1 array index 0",
ItemInfo2: "item info 2 array index 0",
},
ArrayItem{
ItemInfo1: "item info 1 array index 1",
ItemInfo2: "item info 2 array index 1",
},
}
nested := Nested{
NestValue1: "nest value 1",
NestValue2: "nest value 2",
}
jsonResponse := JSONResponse{
Value1: "value 1",
Value2: "value 2",
Nested: nested,
ArrayItems: arrayItems,
}
fmt.Printf("The struct returned before marshalling\n\n")
fmt.Printf("%+v\n\n\n\n", jsonResponse)
// The MarshalIndent function only serves to pretty print, json.Marshal() is what would normally be used
byteArray, err := json.MarshalIndent(jsonResponse, "", " ")
if err != nil {
fmt.Println(err)
}
fmt.Printf("The JSON response returned when the struct is marshalled\n\n")
fmt.Println(string(byteArray))
}
- 第12行:我们将ArrayItems添加到我们的JSONResponse,它是[] ArrayItem类型,ArrayItem类型的数组,我们将在下面声明。
- 第20-23行:声明ArrayItem结构这是数组中每个项目所包含内容的定义。
- 第27-36行:实例化类型为[] ArrayItem的arrayItem,并填充每个索引中的值。
- 第47行:在jsonResponse的声明中引用arrayItems变量。
好的,现在让我们看一下从其他API中使用JSON,我将从API中模拟返回的JSON以简化该过程。由于我们现在已经了解Go结构如何与JSON字符串相关,因此我们将直接使用复杂的JSON对象。
curl [https://httpbin.org/get](https://httpbin.org/get)
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "83.7.252.17, 83.7.252.17",
"url": "https://httpbin.org/get"
}
请注意,“origin”对您来说会有所不同,因为您的请求来自不同的IP。空的“args”对象将包含URL中传递的任何参数。所以https://httpbin.org/get?testArg=testValue&x=3会返回,
"args": {
"testArg": "testValue",
"x": "3"
}
map[string]interface{}interface{}
让我们看一下在代码中使用API中的JSON并讨论文件主要部分的示例。
package main
import (
"encoding/json"
"fmt"
)
type JSONResponse struct {
Args map[string]interface{} `json:"args"`
Headers Headers `json:"headers"`
Origin string `json:"origin"`
Url string `json:"url"`
}
type Headers struct {
Accept string `json:"Accept"`
Host string `json:"Host"`
UserAgent string `json:"User-Agent"`
}
func main() {
jsonString := `{"args": {}, "headers": {"Accept": "*/*", "Host": "httpbin.org", "User-Agent": "curl/7.54.0"}, "origin": "89.7.222.10, 89.7.222.10", "url": "https://httpbin.org/get"}`
var jsonResponse JSONResponse
err := json.Unmarshal([]byte(jsonString), &jsonResponse)
if err != nil {
fmt.Println(err)
}
fmt.Println(jsonResponse)
}
json:"headers"
解析接口
我们现在知道如果我们不确定要在JSON中使用的值类型或键名,我们可以将JSON解析为map [string] interface {}类型。如果我们查看前面的示例并想象值是通过URL(https://httpbin.org/get?testArg=testValue&x=3)传入的结果,
"args": {
"testArg": "testValue",
"x": "3"
}
jsonResponse.Args["testArg"]jsonResponse.Args["x"]
希望这有助于您更好地理解如何在Go中使用JSON。一如既往,欢迎任何反馈,如果我犯了任何错误,请告诉我。