Go如何实现json字符串与各类struct相互转换

 更新时间:2022年08月30日 14:29:57   作者:FeelTouch Labs  
这篇文章主要介绍了Go如何实现json字符串与各类struct相互转换,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

json字符串与各类struct相互转换

不废话了都在代码中了

 
package main 
import (
   "fmt"
   "reflect"
   "encoding/json"
   "strings"
)
 
type Class struct {
   Grade int `json:"grade"` //年级
   ClassNumber int  `json:"classNumber"` //班级号
}
 
type Student struct{
   Name string  //大写开头,可被导出,没有`json:".."`,导出json的字段名是原本名称
   age int  //小写开题,不可被导出
   Hight int `json:"currentHight"` //导出对应json的字段名为currentHight
   Class *Class `class` //指针,指向引用对象;如果不用指针,只是值复制
}
 
func doMarshal(){//对象转json字符串
   nClass:=new(Class)//new只给给特定类型分配内存,设置“零”值,返回其地址(指针)
   fmt.Printf("nClass的类型是%s,内容是%v\n",reflect.TypeOf(nClass),*nClass)
   nClass.Grade=3
   nClass.ClassNumber=6
   nStudents:=make([]*Student,0)
   //make只用于map,slice和channel,并且不显示返回指针
   //这个切片,存放Student的指针
   nStudent:=Student{"Lily",7,116,nClass}
   jsonBytes,err1:=json.Marshal(nStudent)//解析后的是[]byte
   if err1!=nil{
      fmt.Printf("转json失败:%v\n",err1)
      return
   }
   fmt.Println("转成的JSON:") //age不会被导出
   //{"Name":"Lily","currentHight":116,"Class":{"grade":3,"classNumber":6}}
   fmt.Println(string(jsonBytes))
   nStudents=append(nStudents,&Student{"Lilei",8,130,nClass})
   nStudents=append(nStudents,&nStudent)
   josnListBytes,err2:=json.Marshal(nStudents)
   if err2!=nil{
      fmt.Printf("转jsonList失败:%v\n",err2)
      return
   }
   fmt.Println("转成的列表型JSON:")
   fmt.Println(string(josnListBytes))
   //[{"Name":"Lilei","currentHight":130,"Class":{"grade":3,"classNumber":6}},{"Name":"Lily","currentHight":116,"Class":{"grade":3,"classNumber":6}}]
}
 
func doUnMarshal(){//json字符串转对象
   jsonStr:=`
      {
         "Name":"Lily",
         "currentHight":116,
         "age":12,
         "Class":{
            "grade":3,
            "classNumber":6
         },
         "score":[98,100,95]
      }
   `
   jsonListStr:=`[
      {
         "Name":"Lucy",
         "currentHight":120,
         "Class":{
            "grade":3,
            "classNumber":5
         }
      },
      {
         "Name":"Lily",
         "currentHight":116,
         "Class":{
            "grade":3,
            "classNumber":6
         }
      }
   ]`
   //第一种解析json方式,解析到Struct/[]Struct
   student:=Student{}//同new(Student)
   err:=json.Unmarshal([]byte(jsonStr),&student)
   //Unmarshall第2个参数必须是指针,否则报错:json: Unmarshal(non-pointer main.Student)
   //因为必须解析到具体的对象,所以需传入对象引用,而不是值传递
   //score在Student中没有此字段,所以被忽略了
   if err!=nil{
      fmt.Printf("解析json字符串异常:%s\n",err)
   }
   fmt.Printf("学生的名称是%v,班级信息是%v,年龄是%v(私有对象不能导入,初始为0)\n",student.Name,*student.Class,student.age)
   //学生的名称是Lily,学生的班级信息是{3 6},学生的年龄是0
   students:=[]*Student{} //定义切片,同make([]*Student,0)
   err=json.Unmarshal([]byte(jsonListStr),&students)
   if err!=nil{
      fmt.Printf("解析json字符串异常:%s\n",err)
   }
   for _,stu:=range students{ //这里stu是指针类型,获取其属性可以直接用.Name,也可以解引用后用.Name
      fmt.Printf("列表:学生的名称是%s,身高是%d,在%d年级%d班\n",stu.Name,(*stu).Hight,(*stu.Class).Grade,stu.Class.ClassNumber)
   }
   //第二种解析到interface{}/[]interface{}
   fmt.Println("*************解析json*************")
   var student1 interface{}
   err=json.Unmarshal([]byte(jsonStr),&student1)
   if err!=nil{
      fmt.Printf("解析json字符串异常:%s\n",err)
   }
   c:=-1
   resolve2JosnObj(student1,c)
   /*
   *************解析json*************
   map元素:
   map[Name]的元素: 类型是string,值是 Lily
   map[currentHight]的元素: 类型float64,值是 116
   map[age]的元素: 类型float64,值是 12
   map[Class]的元素: map元素:
   ---map[classNumber]的元素: 类型float64,值是 6
   ---map[grade]的元素: 类型float64,值是 3
   map[score]的元素: list元素:
   ---第0个元素: 类型float64,值是 98
   ---第1个元素: 类型float64,值是 100
   ---第2个元素: 类型float64,值是 95
    */
   fmt.Println("*************解析jsonlist*************")
   var students1 interface{}
   err=json.Unmarshal([]byte(jsonListStr),&students1)
   if err!=nil{
      fmt.Printf("解析jsonlist字符串异常:%s\n",err)
   }
   d:=-1
   resolve2JosnObj(students1,d)
   /*
   *************解析jsonlist*************
   list元素:
   第0个元素: map元素:
   ---map[Name]的元素: 类型是string,值是 Lucy
   ---map[currentHight]的元素: 类型float64,值是 120
   ---map[Class]的元素: map元素:
   ------map[grade]的元素: 类型float64,值是 3
   ------map[classNumber]的元素: 类型float64,值是 5
   第1个元素: map元素:
   ---map[Class]的元素: map元素:
   ------map[grade]的元素: 类型float64,值是 3
   ------map[classNumber]的元素: 类型float64,值是 6
   ---map[Name]的元素: 类型是string,值是 Lily
   ---map[currentHight]的元素: 类型float64,值是 116
    */
}
 
func resolve2JosnObj(objI interface{},c int){
   c=c+1
   switch obj:=objI.(type) { //此处[interface{}].(type) 专门用于switch的类型判断
   case string:
      fmt.Println("类型是string,值是",obj)
   case float64:
      fmt.Println("类型float64,值是",obj)
   case map[string]interface{}:
      fmt.Println("map元素:")
      for k,vi:=range obj{
         fmt.Printf("%smap[%s]的元素: ",strings.Repeat("---",c),k)
         resolve2JosnObj(vi,c)
      }
   case []interface{}:
      fmt.Println("list元素:")
      for i,vi:=range obj{
         fmt.Printf("%s第%d个元素: ",strings.Repeat("---",c),i)
         resolve2JosnObj(vi,c)
      }
 
   default:
      fmt.Println("无法判断类型,类型是",reflect.TypeOf(obj),"值是",obj) 
   } 
}
 
func main() {
   doMarshal()//对象转json字符串
   doUnMarshal()
}

简单总结

1、结构体对象可生成json字符串,Marshal()是[]byte,需要string去转换

2、json字符串可以映射到一个struct,但仅限公共元素(大写开头);也可通用的转换到空接口interfece[],使用对应转换到需要的内容

结构体转换为JSON字符串的一个坑

通过json.Marshal来将结构体数据转换为json字符串时,需要注意结构体内成员变量的首字母大小写的问题,很容易会掉进坑里.

来看一下这个例子

package main
import (
	"encoding/json"
	"fmt"
)
type Student struct {
	Name string
	age int
}
func main() {
	var s Student = Student {
		Name: "xiaomo",
		age: 18,
	}
	fmt.Printf("%+v\n", s)
	res, _ := json.Marshal(s)
	fmt.Println(string(res))
}

运行输出如下:

$ go run test_json.go
{Name:xiaomo age:18}
{"Name":"xiaomo"}

可以看到转换的json字符串中只包含了Name字段,age字段被忽略了.这是由于在进行json解析时,只会转换结构体能够导出的字段(首字母大写),其他字段将会被忽略.

这个机制也有个好处,可以根据实际需要,将想要导出字段的名字首字母大写,其他字段首字母小写隐藏起来即可.

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 详解golang中模板的常用语法

    详解golang中模板的常用语法

    这篇文章主要介绍了golang模板中的常用语法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • 一文搞懂Go语言中defer关键字的使用

    一文搞懂Go语言中defer关键字的使用

    defer是golang中用的比较多的一个关键字,也是go面试题里经常出现的问题。今天就来整理一下关于defer的学习使用,希望对需要的朋友有所帮助
    2022-09-09
  • Golang日志库logrus的介绍与使用示例代码

    Golang日志库logrus的介绍与使用示例代码

    Logrus是Go语言的一个功能丰富的日志库,支持结构化日志和多级别日志记录,它兼容标准log库,并可通过自定义Hooks和Formatter进行高度定制化,支持集成如syslog等系统,便于管理和分析,Logrus还支持自定义日志颜色和格式,以及根据日志级别进行不同处理,如panic和exit
    2024-10-10
  • Go 实现热重启的详细介绍

    Go 实现热重启的详细介绍

    这篇文章主要介绍了Go 实现热重启的详细介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Go语言流程控制语句

    Go语言流程控制语句

    这篇文章介绍了Go语言流程控制语句的用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Go重写http请求重定向的方法

    Go重写http请求重定向的方法

    当使用Go语言进行 HTTP 请求时,默认情况下,http.Client 会自动处理服务器返回的重定向响应(3xx 状态码),本文将详细介绍如何在 Go 中实现禁止 HTTP 请求的重定向、限制重定向次数以及添加自定义重定向策略,需要的朋友可以参考下
    2024-08-08
  • 详解go语言判断管道是否关闭的常见误区

    详解go语言判断管道是否关闭的常见误区

    这篇文章主要想和大家一起探讨一下在Go语言中,我们是否可以使用读取管道时的第二个返回值来判断管道是否关闭,文中的示例代码讲解详细,有兴趣的可以了解下
    2023-10-10
  • Go语言中的IO操作及Flag包的用法

    Go语言中的IO操作及Flag包的用法

    这篇文章介绍了Go语言中的IO操作及Flag包的用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Golang error使用场景介绍

    Golang error使用场景介绍

    我们在使用Golang时,不可避免会遇到异常情况的处理,与Java、Python等语言不同的是,Go中并没有try...catch...这样的语句块,这个时候我们如何才能更好的处理异常呢?本文来教你正确方法
    2023-03-03
  • 一文让你理解go语言的Context

    一文让你理解go语言的Context

    在Go语言中,Context(上下文)是一个类型,用于在程序中传递请求范围的值、截止时间、取消信号和其他与请求相关的上下文信息,它在多个goroutine之间传递这些值,使得并发编程更加可靠和简单,本文详细介绍go语言的Context,需要的朋友可以参考下
    2023-05-05

最新评论