encoding/json库

Marshal/Unmarshal

Marshal/Unmarshal:将JSON数据编码为Go语言中的结构体类型,或将Go语言的结构体类型解码为JSON数据

结构体转为 JSON 字符串

可以使用 json.Marshal() 函数将一个 Go 结构体类型的值转换为对应的 JSON 字符串。例如:

type Person struct {
    Name string`json:"name"`
    Age  int`json:"age"`
}

p := Person{"Alice", 28}
bytes, err := json.Marshal(p)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(bytes)) // {"name":"Alice","age":28}

在结构体定义中,通过 json 标签来指定结构体字段在 JSON 中对应的键名。在这个例子中,Name 对应的键名为 "name"Age 对应的键名为 "age"

JSON 字符串转为结构体

可以使用 json.Unmarshal() 函数将一个 JSON 字符串转换为对应的 Go 结构体类型的值。例如:
type Person struct {
    Name string`json:"name"`
    Age  int`json:"age"`
}

var p Person
err := json.Unmarshal([]byte(`{"name":"Alice","age":28}`), &p)
if err != nil {
    log.Fatal(err)
}
fmt.Println(p.Name, p.Age) // Alice 28

在调用 json.Unmarshal() 函数时,需要传入一个字节数组和一个指向目标结构体的指针。json.Unmarshal() 函数会将 JSON 数据解析后存储到指向目标结构体的指针中。

处理未知 JSON 字段

在解析 JSON 数据时,如果目标结构体中包含了未知的 JSON 字段,json.Unmarshal() 函数会返回一个错误。可以使用 json.RawMessage 类型来处理未知 JSON 字段。例如:

type Person struct {
    Name      string`json:"name"`
    Age       int`json:"age"`
    ExtraData json.RawMessage `json:"-"`
}

var p Person
err := json.Unmarshal([]byte(`{"name":"Alice","age":28,"gender":"female"}`), &p)
if err != nil {
    log.Fatal(err)
}
fmt.Println(p.Name, p.Age) // Alice 28
fmt.Println(string(p.ExtraData)) // {"gender":"female"}

在这个例子中,Person 结构体中多了一个 ExtraData 字段,它的类型为 json.RawMessage,并且指定了一个空的 json 标签。json.RawMessage 类型是一个字节数组,可以存储未知的 JSON 字段。

忽略空值字段

在将 Go 结构体类型的值转换为 JSON 字符串时,json.Marshal() 函数会将所有的零值字段都转换为 JSON 字符串中的 null 值。如果需要忽略空值字段,可以使用 omitempty 标记。例如:

type Person struct {
    Name string`json:"name,omitempty"`
    Age  int`json:"age,omitempty"`
}

解码器和编码器

在 Go 中,JSON 解码器和编码器是使用 encoding/json 包实现的。这个包提供了一些方法来将 Go 数据结构编码为 JSON 字符串或将 JSON 字符串解码为 Go 数据结构。

JSON 解码器和编码器的主要用途是在网络通信和数据存储中,将结构化的数据转换为可传输或可存储的格式,或者将从网络或存储中读取的数据转换为可用的数据结构。

具体来说,JSON 解码器可以将从网络或文件读取的 JSON 字符串解析为 Go 数据结构。这些数据结构可以是原生类型,如字符串和数字,也可以是自定义的结构体、数组和切片等复杂类型。解码器的另一个重要功能是检查 JSON 字符串的有效性,以防止出现格式错误或类型不匹配的情况。

JSON 编码器可以将 Go 数据结构编码为 JSON 字符串,以便将它们发送到网络或保存到文件中。编码器还可以控制生成的 JSON 字符串的格式,例如是否缩进、缩进字符等等。

使用 JSON 解码器和编码器,可以很方便地实现不同系统之间的数据交换和存储,使得数据传输和存储更加高效和可靠。同时,JSON 也是一种通用的数据交换格式,在 Web 开发中也被广泛使用,例如在 RESTful API 中使用 JSON 作为数据传输格式

创建 JSON 解码器

创建 JSON 解码器的过程非常简单,可以直接调用 json.NewDecoder(io.Reader) 函数来创建。

package main

import (
    "encoding/json""fmt""strings"
)

func main() {
    // 准备 JSON 字符串
    jsonData := `{"name":"gopher","age":18}`// 将 JSON 字符串转换为 io.Reader 接口
    reader := strings.NewReader(jsonData)

    // 创建 JSON 解码器
    decoder := json.NewDecoder(reader)

    // 解码 JSON 数据var data map[string]interface{}
    if err := decoder.Decode(&data); err != nil {
        panic(err)
    }

    // 输出解码后的数据
    fmt.Println(data)
}

上述代码中,我们首先准备了一个 JSON 格式的字符串,然后通过 strings.NewReader() 函数将其转换为 io.Reader 接口,接着使用 json.NewDecoder() 函数创建了一个 JSON 解码器,最后通过调用 decoder.Decode() 方法来解码 JSON 数据。

创建 JSON 编码器

创建 JSON 编码器也很简单,可以直接调用 json.NewEncoder(io.Writer) 函数来创建。

package main

import (
    "encoding/json""fmt""os"
)

func main() {
    // 创建一个数据结构
    data := map[string]interface{}{
        "name": "gopher",
        "age":  18,
    }

    // 创建 JSON 编码器
    encoder := json.NewEncoder(os.Stdout)

    // 编码数据并输出到标准输出if err := encoder.Encode(data); err != nil {
        panic(err)
    }
}

上述代码中,我们首先创建了一个数据结构,然后通过 json.NewEncoder() 函数创建了一个 JSON 编码器,最后通过调用 encoder.Encode() 方法将数据编码成 JSON 格式字符串并输出到标准输出流中

Valid有效JSON

使用 json.Valid() 函数可以进行检查。Valid() 函数接受一个字节数组,如果字节数组包含有效的 JSON 数据,则返回 true,否则返回 false

以下是使用 Valid() 函数的示例代码:

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	// 有效的 JSON 字符串
	validJSON := []byte(`{"name": "Alice", "age": 25}`)

	// 无效的 JSON 字符串
	invalidJSON := []byte(`{"name": "Bob", "age": }`)

	// 检查有效的 JSON 数据
	if json.Valid(validJSON) {
		fmt.Println("validJSON is valid JSON data")
	} else {
		fmt.Println("validJSON is not valid JSON data")
	}

	// 检查无效的 JSON 数据
	if json.Valid(invalidJSON) {
		fmt.Println("invalidJSON is valid JSON data")
	} else {
		fmt.Println("invalidJSON is not valid JSON data")
	}
}

输出:

validJSON is valid JSON data
invalidJSON is not valid JSON data

在此示例中,Valid() 函数用于检查两个不同的 JSON 字符串,一个是有效的 JSON 数据,另一个是无效的 JSON 数据。在第一次调用 Valid() 函数时,它返回 true,因为 validJSON 包含有效的 JSON 数据。在第二次调用 Valid() 函数时,它返回 false,因为 invalidJSON 包含无效的 JSON 数据。

在实际使用中,可以使用 Valid() 函数来检查从外部获取的 JSON 数据是否包含有效的 JSON 数据,以避免因无效数据而导致程序崩溃。

格式化JSON数据

Indent 函数用于对 JSON 数据进行缩进处理,使其更具可读性。

Indent 函数的声明如下:

funcIndent(dst *bytes.Buffer, src []byte, prefix, indent string)error

参数说明:

  • dst:输出缓冲区。

  • src:要缩进的 JSON 数据。

  • prefix:每一行输出的前缀,可以是空字符串。

  • indent:每一级缩进的字符串,一般是空格或者 tab。

Indent 函数的返回值是一个 error 类型,如果缩进操作出现错误,会返回一个非 nil 的错误值。

下面是一个简单的示例代码:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
)

func main() {
	data := map[string]interface{}{
		"Name":    "Tom",
		"Age":     20,
		"Address": "Beijing",
	}

	jsonData, _ := json.Marshal(data)

	var buffer bytes.Buffer
	if err := json.Indent(&buffer, jsonData, "", "  "); err != nil {
		fmt.Println("Indent error:", err)
		return
	}

	fmt.Println(buffer.String())
}

运行结果如下:

{"Address":"Beijing","Age":20,"Name":"Tom"}

在上面的示例中,我们首先定义了一个包含三个字段的 map 类型的变量 data,然后使用 json.Marshal 函数将其转换成 JSON 数据。

接着,我们定义了一个 bytes.Buffer 类型的变量 buffer,并将其作为输出缓冲区传递给 Indent 函数。在调用 Indent 函数时,我们传递了 jsonData 作为要缩进的 JSON 数据,"" 作为每一行输出的前缀,以及两个空格作为每一级缩进的字符串。

最后,我们通过调用 buffer.String() 将缩进后的 JSON 数据输出到控制台。

需要注意的是,在实际开发中,如果要将 JSON 数据以缩进格式输出到文件或者网络连接中,可以将 bytes.Buffer 类型的变量替换成 os.File 或者 net.Conn 类型的变量

RawMessage任何类型

RawMessage 类型是用于将任何 JSON 数据作为未处理的字节序列表示的类型。具体来说,RawMessage 是一个 []byte 类型的别名,它可以存储任何有效的 JSON 数据,包括对象、数组、字符串、数字、布尔和 null 值。

RawMessage 类型最常见的用途是在处理 JSON 数据时,当你想要将未知的 JSON 数据解码为一个通用的数据类型时。例如,在处理一些 JSON API 的响应时,你可能会遇到不同结构的 JSON 数据,此时就可以使用 RawMessage 来表示未知的 JSON 数据。

下面是一个使用 RawMessage 的示例:

type Response struct {
    RawData json.RawMessage `json:"data"`
}

func main() {
    jsonData := []byte(`{"data": {"name": "John", "age": 30}}`)
    response := &Response{}
    if err := json.Unmarshal(jsonData, response); err != nil {
        log.Fatal(err)
    }

    // 解析 RawMessagevar data map[string]interface{}
    if err := json.Unmarshal(response.RawData, &data); err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Name: %s\n", data["name"])
    fmt.Printf("Age: %d\n", int(data["age"].(float64)))
}

在上面的例子中,我们定义了一个 Response 结构体,它包含一个名为 RawDataRawMessage 类型的字段。在解码 JSON 数据时,我们将 JSON 数据解码为 Response 类型,然后可以使用 json.UnmarshalRawMessage 字段解码为一个通用的 map[string]interface{} 类型。这样我们就可以在代码中使用通用类型访问未知的 JSON 数据了。

需要注意的是,由于 RawMessage 仅仅是存储未处理的字节序列,因此你需要自己处理它们,比如将它们解码为正确的数据类型。同时,RawMessage 也需要保证存储的 JSON 数据是有效的,否则在解码时可能会发生错误。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值