Golang 语言中怎么解码 4 种常见JSON 格式数据?

简介: Golang 语言中怎么解码 4 种常见JSON 格式数据?

介绍

工作中我们经常会遇到解码JSON格式的数据,本文通过4个示例介绍工作中常用到的四种 JSON格式。在 Golang语言中,通常是使用标准库的encoding/json包中的函数Unmarshal解码JSON格式的数据,下面我们先介绍一下该函数如何使用,再通过4个示例代码来演示一下如何在Golang中解码常见的4种JSON格式的数据。

func Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal函数解析json编码的数据并将结果存入v指向的值。

Unmarshal和Marshal做相反的操作,必要时申请映射、切片或指针,有如下的附加规则:

要将json数据解码写入一个指针,Unmarshal函数首先处理json数据是json字面值null的情况。此时,函数将指针设为nil;否则,函数将json数据解码写入指针指向的值;如果指针本身是nil,函数会先申请一个值并使指针指向它。

要将json数据解码写入一个结构体,函数会匹配输入对象的键和Marshal使用的键(结构体字段名或者它的标签指定的键名),优先选择精确的匹配,但也接受大小写不敏感的匹配。

要将json数据解码写入一个接口类型值,函数会将数据解码为如下类型写入接口:

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

如果一个JSON值不匹配给出的目标类型,或者如果一个json数字写入目标类型时溢出,Unmarshal函数会跳过该字段并尽量完成其余的解码操作。如果没有出现更加严重的错误,本函数会返回一个描述第一个此类错误的详细信息的UnmarshalTypeError。

JSON的null值解码为go的接口、指针、切片时会将它们设为nil,因为null在json里一般表示“不存在”。解码json的null值到其他go类型时,不会造成任何改变,也不会产生错误。

当解码字符串时,不合法的utf-8或utf-16代理(字符)对不视为错误,而是将非法字符替换为unicode字符U+FFFD。

03

普通 JSON

示例代码:

package main
import (
 "encoding/json"
 "fmt"
)
// Actress 女演员
type Actress struct {
 Name       string
 Birthday   string
 BirthPlace string
 Opus       []string
}
func main() {
 // 普通JSON
 // 因为json.UnMarshal() 函数接收的参数是字节切片,所以需要把JSON字符串转换成字节切片。
 jsonData := []byte(`{
  "name":"迪丽热巴",
  "birthday":"1992-06-03",
  "birthPlace":"新疆乌鲁木齐市",
  "opus":[
   "《阿娜尔罕》",
   "《逆光之恋》",
   "《克拉恋人》"
  ]
 }`)
 var actress Actress
 err := json.Unmarshal(jsonData, &actress)
 if err != nil {
  fmt.Println("error:", err)
  return
 }
 fmt.Printf("姓名:%s\n", actress.Name)
 fmt.Printf("生日:%s\n", actress.Birthday)
 fmt.Printf("出生地:%s\n", actress.BirthPlace)
 fmt.Println("作品:")
 for _, val := range actress.Opus {
  fmt.Println("\t", val)
 }
}

output:

姓名:迪丽热巴
生日:1992-06-03
出生地:新疆乌鲁木齐市
作品:
  《阿娜尔罕》
  《逆光之恋》
  《克拉恋人》

04

JSON 内嵌普通 JSON

示例代码:

package main
import (
 "encoding/json"
 "fmt"
)
// Opus 作品
type Opus struct {
 Date string
 Title string
}
// Actress 女演员
type Actress struct {
 Name       string
 Birthday   string
 BirthPlace string
 Opus       Opus
}
func main () {
 // JSON嵌套普通JSON
 jsonData := []byte(`{
  "name":"迪丽热巴",
  "birthday":"1992-06-03",
  "birthPlace":"新疆乌鲁木齐市",
  "opus": {
   "Date":"2013",
   "Title":"《阿娜尔罕》"
  }
 }`)
 var actress Actress
 err := json.Unmarshal(jsonData, &actress)
 if err != nil {
  fmt.Println("error:", err)
  return
 }
 fmt.Printf("姓名:%s\n", actress.Name)
 fmt.Printf("生日:%s\n", actress.Birthday)
 fmt.Printf("出生地:%s\n", actress.BirthPlace)
 fmt.Println("作品:")
 fmt.Printf("\t%s:%s", actress.Opus.Date, actress.Opus.Title)
}

output:

姓名:迪丽热巴
生日:1992-06-03
出生地:新疆乌鲁木齐市
作品:
 2013:《阿娜尔罕》

05

JSON 内嵌数组 JSON

示例代码:

package main
import (
 "encoding/json"
 "fmt"
)
type Opus struct {
 Date string
 Title string
}
type Actress struct {
 Name string
 Birthday string
 BirthPlace string
 Opus []Opus
}
func main () {
 // JSON嵌套数组JSON
 jsonData := []byte(`{
  "name":"迪丽热巴",
  "birthday":"1992-06-03",
  "birthPlace":"新疆乌鲁木齐市",
  "opus":[
   {
    "date":"2013",
    "title":"《阿娜尔罕》"
   },
   {
    "date":"2014",
    "title":"《逆光之恋》"
   },
   {
    "date":"2015",
    "title":"《克拉恋人》"
   }
  ]
 }`)
 var actress Actress
 err := json.Unmarshal(jsonData, &actress)
 if err != nil {
  fmt.Println("error:", err)
  return
 }
 fmt.Printf("姓名:%s\n", actress.Name)
 fmt.Printf("生日:%s\n", actress.Birthday)
 fmt.Printf("出生地:%s\n", actress.BirthPlace)
 fmt.Println("作品:")
 for _, val := range actress.Opus {
  fmt.Printf("\t%s - %s\n", val.Date, val.Title)
 }
}

output:

姓名:迪丽热巴
生日:1992-06-03
出生地:新疆乌鲁木齐市
作品:
 2013 - 《阿娜尔罕》
 2014 - 《逆光之恋》
 2015 - 《克拉恋人》

06

JSON 内嵌具有动态 Key 的 JSON

示例代码:

package main
import (
 "encoding/json"
 "fmt"
)
// Opus 作品
type Opus struct {
 Type string
 Title string
}
// Actress 女演员
type Actress struct {
 Name string
 Birthday string
 BirthPlace string
 Opus map[string]Opus
}
func main () {
 jsonData := []byte(`{
  "name":"迪丽热巴",
  "birthday":"1992-06-03",
  "birthPlace":"新疆乌鲁木齐市",
  "opus":{
   "2013":{
    "Type":"近代革命剧",
    "Title":"《阿娜尔罕》"
   },
   "2014":{
    "Type":"奇幻剧",
    "Title":"《逆光之恋》"
   },
   "2015":{
    "Type":"爱情剧",
    "Title":"《克拉恋人》"
   }
  }
 }`)
 var actress Actress
 err := json.Unmarshal(jsonData, &actress)
 if err != nil {
  fmt.Println("error:", err)
  return
 }
 fmt.Printf("姓名:%s\n", actress.Name)
 fmt.Printf("生日:%s\n", actress.Birthday)
 fmt.Printf("出生地:%s\n", actress.BirthPlace)
 fmt.Println("作品:")
 for index, value := range actress.Opus {
  fmt.Printf("\t日期:%s\n", index)
  fmt.Printf("\t\t分类:%s\n", value.Type)
  fmt.Printf("\t\t标题:%s\n", value.Title)
 }
}

output:

姓名:迪丽热巴
生日:1992-06-03
出生地:新疆乌鲁木齐市
作品:
 日期:2013
  分类:近代革命剧
  标题:《阿娜尔罕》
 日期:2014
  分类:奇幻剧
  标题:《逆光之恋》
 日期:2015
  分类:爱情剧
  标题:《克拉恋人》

07

总结

我们先是介绍了Golang标准库的encoding/json包中的Unmarshal函数,然后通过上面4个示例代码,分别介绍了如何解码以下4种JSON格式数据:

JSON格式1:

{
 "name":"迪丽热巴",
 "birthday":"1992-06-03",
 "birthPlace":"新疆乌鲁木齐市",
 "opus":[
  "《阿娜尔罕》",
  "《逆光之恋》",
  "《克拉恋人》"
 ]
}

JSON格式2:

{
 "name":"迪丽热巴",
 "birthday":"1992-06-03",
 "birthPlace":"新疆乌鲁木齐市",
 "opus": {
  "Date":"2013",
  "Title":"《阿娜尔罕》"
 }
}

JSON格式3:

{
 "name":"迪丽热巴",
 "birthday":"1992-06-03",
 "birthPlace":"新疆乌鲁木齐市",
 "opus":[
  {
   "date":"2013",
   "title":"《阿娜尔罕》"
  },
  {
   "date":"2014",
   "title":"《逆光之恋》"
  },
  {
   "date":"2015",
   "title":"《克拉恋人》"
  }
 ]
}

JSON格式4:

{
 "name":"迪丽热巴",
 "birthday":"1992-06-03",
 "birthPlace":"新疆乌鲁木齐市",
 "opus":{
  "2013":{
   "Type":"近代革命剧",
   "Title":"《阿娜尔罕》"
  },
  "2014":{
   "Type":"奇幻剧",
   "Title":"《逆光之恋》"
  },
  "2015":{
   "Type":"爱情剧",
   "Title":"《克拉恋人》"
  }
 }
}

推荐阅读:

Golang 语言的编程技巧之类型

参考资料:

https://golang.org/pkg/encoding/json/#Unmarshal 


目录
相关文章
|
22小时前
|
存储 缓存 安全
Golang深入浅出之-Go语言中的并发安全容器:sync.Map与sync.Pool
Go语言中的`sync.Map`和`sync.Pool`是并发安全的容器。`sync.Map`提供并发安全的键值对存储,适合快速读取和少写入的情况。注意不要直接遍历Map,应使用`Range`方法。`sync.Pool`是对象池,用于缓存可重用对象,减少内存分配。使用时需注意对象生命周期管理和容量控制。在多goroutine环境下,这两个容器能提高性能和稳定性,但需根据场景谨慎使用,避免不当操作导致的问题。
14 4
|
23小时前
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第2天】Go语言的并发编程基于CSP模型,强调通过通信共享内存。核心概念是goroutines(轻量级线程)和channels(用于goroutines间安全数据传输)。常见问题包括数据竞争、死锁和goroutine管理。避免策略包括使用同步原语、复用channel和控制并发。示例展示了如何使用channel和`sync.WaitGroup`避免死锁。理解并发原则和正确应用CSP模型是编写高效安全并发程序的关键。
18 4
|
1天前
|
JSON JavaScript Java
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
7 0
|
1天前
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第1天】Go语言基于CSP理论,借助goroutines和channels实现独特的并发模型。Goroutine是轻量级线程,通过`go`关键字启动,而channels提供安全的通信机制。文章讨论了数据竞争、死锁和goroutine泄漏等问题及其避免方法,并提供了一个生产者消费者模型的代码示例。理解CSP和妥善处理并发问题对于编写高效、可靠的Go程序至关重要。
9 2
|
1天前
|
设计模式 Go 调度
Golang深入浅出之-Go语言中的并发模式:Pipeline、Worker Pool等
【5月更文挑战第1天】Go语言并发模拟能力强大,Pipeline和Worker Pool是常用设计模式。Pipeline通过多阶段处理实现高效并行,常见问题包括数据竞争和死锁,可借助通道和`select`避免。Worker Pool控制并发数,防止资源消耗,需注意任务分配不均和goroutine泄露,使用缓冲通道和`sync.WaitGroup`解决。理解和实践这些模式是提升Go并发性能的关键。
14 2
|
1天前
|
JSON 监控 安全
Golang深入浅出之-Go语言中的反射(reflect):原理与实战应用
【5月更文挑战第1天】Go语言的反射允许运行时检查和修改结构,主要通过`reflect`包的`Type`和`Value`实现。然而,滥用反射可能导致代码复杂和性能下降。要安全使用,应注意避免过度使用,始终进行类型检查,并尊重封装。反射的应用包括动态接口实现、JSON序列化和元编程。理解反射原理并谨慎使用是关键,应尽量保持代码静态类型。
11 2
|
1天前
|
Go
Golang深入浅出之-Go语言代码质量与规范:遵循Gofmt与Linting
【5月更文挑战第1天】本文讨论了如何使用`gofmt`和Lint工具提升Go代码质量。`gofmt`负责自动格式化代码,保持风格统一,而Lint工具如`golint`、`govet`、`staticcheck`则进行静态分析,检查潜在错误和未使用的变量。通过集成`gofmt`检查到CI/CD流程,避免格式冲突,并使用Lint工具发现并修复问题,如未处理的错误、不规范命名。遵循这些最佳实践,可提高代码可读性、团队协作效率和可维护性。
9 3
|
2天前
|
Go 开发者
Golang深入浅出之-Go语言项目构建工具:Makefile与go build
【4月更文挑战第27天】本文探讨了Go语言项目的构建方法,包括`go build`基本命令行工具和更灵活的`Makefile`自动化脚本。`go build`适合简单项目,能直接编译Go源码,但依赖管理可能混乱。通过设置`GOOS`和`GOARCH`可进行跨平台编译。`Makefile`适用于复杂构建流程,能定义多步骤任务,但编写较复杂。在选择构建方式时,应根据项目需求权衡,从`go build`起步,逐渐过渡到Makefile以实现更高效自动化。
12 2
|
2天前
|
存储 Go
Golang深入浅出之-Go语言依赖管理:GOPATH与Go Modules
【4月更文挑战第27天】Go语言依赖管理从`GOPATH`进化到Go Modules。`GOPATH`时代,项目结构混乱,可通过设置多个工作空间管理。Go Modules自Go 1.11起提供更现代的管理方式,通过`go.mod`文件控制依赖。常见问题包括忘记更新`go.mod`、处理本地依赖和模块私有化,可使用`go mod tidy`、`replace`语句和`go mod vendor`解决。理解并掌握Go Modules对现代Go开发至关重要。
11 2
|
2天前
|
安全 测试技术 Go
Golang深入浅出之-Go语言单元测试与基准测试:testing包详解
【4月更文挑战第27天】Go语言的`testing`包是单元测试和基准测试的核心,简化了测试流程并鼓励编写高质量测试代码。本文介绍了测试文件命名规范、常用断言方法,以及如何进行基准测试。同时,讨论了测试中常见的问题,如状态干扰、并发同步、依赖外部服务和测试覆盖率低,并提出了相应的避免策略,包括使用`t.Cleanup`、`t.Parallel()`、模拟对象和检查覆盖率。良好的测试实践能提升代码质量和项目稳定性。
8 1