Go语言结构体(struct)详解:定义、使用与JSON编码
在Go语言中,结构体(struct)是一种非常重要的复合数据类型,它允许开发者将不同类型的数据组合在一起,形成更复杂的对象结构。结构体不仅用于数据的组织和管理,还广泛应用于网络编程、Web开发和数据序列化等领域。掌握Go语言中的结构体,不仅能提升代码的可读性与可维护性,还能帮助开发者更高效地构建应用程序。本文将详细介绍Go语言结构体的定义、使用方式,以及如何将结构体数据转换为JSON格式,帮助你在实际开发中灵活运用。
本文深入探讨了Go语言中的结构体(struct)类型,首先介绍了结构体的基本概念和声明方式,然后通过实例讲解了如何初始化、复制和传递结构体数据。接着,我们将重点讨论如何通过结构体编码和解码JSON数据,包括如何使用Go的json包进行数据序列化,以及如何通过结构体标签自定义JSON字段名的映射。最后,文中还提供了一些练习题,帮助读者巩固所学知识。
结构体
结构类型(struct)
- 为了将分散的零件组成一个完整的结构体,Go提供了struct类型。
- struct允许你将不同类型的东西组合在一起。
- 声明结构
package main
func distance(lat1, long1, lat2, long2 float64) float64 {
return 0.0
}
func main() {
var curiosity struct {
lat float64
long float64
}
curiosity.lat = -4.5895
curiosity.long = 137.4417
fmt.Println(curiosity.lat, curiosity.long)
fmt.Println(curiosity)
}
小测试
- 与独立的变量相比,使用struct的优势是什么?
- 上例中,如果curiosity有一个海拔(altitude)字段,那么你如何给它赋值为-4400?
通过类型复用结构体
package main
func distance(loc1, loc2 location) dis {
return dis{0.0, 0.0}
}
type location struct {
lat float64
long float64
}
// type dis location
type dis struct {
lat float64
long float64
}
func main() {
//var curiosity struct {
// lat float64
// long float64
//}
//type location struct {
//lat float64
// long float64
// }
var spirit location
spirit.lat = -14.5684
spirit.long = 175.472636
var opportunity location
opportunity.lat = -1.9462
opportunity.long = 354.4734
fmt.Println(spirit, opportunity)
}
小测试
- 修改上面例子的代码,改用location类型表示好奇号火星探测器的位置
通过复合字面值初始化struct
-
两种形式:
- 通过成对的字段和值进行初始化
- 按字段定义的顺序进行初始化
package main
import "fmt"
func main() {
type location struct {
lat, long float64
}
opportunity := location{lat: -1.9462, long: 354.4734}
fmt.Println(opportunity)
insight := location{lat: 4.5, long: 135.9}
fmt.Println(insight)
spirit := location{-14.5684, 175.472636}
fmt.Println(spirit)
}
- 打印struct
pakcage main
import "fmt"
func main() {
type location struct {
lat, long float64
}
curiosity := location{-4.5859, 137.4417}
fmt.Printf("%v\n", curiosity)
fmt.Printf("%+v\n", curiosity)
}
- %v,打印出{-4.5895 137.4417}
- %+v,打印出{lat:-4.5895 long:137.4417}
小测试
- 与只给定值的初始化方式相比,成对给定字段和值的初始化方式有哪些优势?
struct的复制
pakcage main
import "fmt"
func main() {
type location struct {
lat, long float64
}
bradbury := location{-4.5859, 137.4417}
curiosity := bradbury
curiosity.long += 0.0106
fmt.Println(bradbury, curiosity)
}
小测试
- 如果将curiosity变量传递给函数,并在函数中对lat和long字段进行修改,那么调用者是否会看到这些变化?
由结构体组成的slice
package main
import "fmt"
func main() {
type location struct {
name string
lat float64
long float64
}
lats := []float64{-4.5859, -14.5684, -1.9462}
longs := []float64{137.4417, 175.472636, 354.4734}
locations := []location{
{name: "Bradbury Landing", lat: -4.5859, long: 137.4417},
{name: "Columbia Memorial Station", lat: -14.5684, long: 175.472636},
{name: "Challenger Memorial Station", lat: -1.9462, long: 354.4734},
}
fmt.Println(lats, longs, locations)
}
小测试
- 使用多个相互关联的slice有什么坏处?
将struct编码为JSON
- JSON(JavaScript Object Notation,JavaScript对象表示法)
- 常用于Web API
- json包的Marshal函数可以将struct中的数据转化为JSON格式。
package main
import (
"encoding/json"
"fmt"
"os"
)
func main() {
type location struct {
Lat, Long, float64
}
curiosity := location{-4.5895, 137.4417}
bytes, err := json.Marshal(curiosity)
exitOnError(err)
fmt.Println(string(bytes))
}
// exitOnError prints any errors and exits.
func exitOnError(err error) {
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
- Marshal函数只会对struct中被导出的字段进行编码。
小测试
- JSON代表什么意思?
使用struct标签来自定义JSON
- Go语言中的json包要求struct中的字段必须以大写字母开头,类似CamelCase驼峰型命名规范。
- 但有时候我们需要snake_case蛇形命名规范,那么该怎么办?
- 可以为字段注明标签,使得json包在进行编码的时候能够按照标签里的样式修改字段名。
package main
import (
"encoding/json"
"fmt"
"os"
)
func main() {
type location struct {
Lat float64 `json: "latitude"`
Long, float64 `json: "longitude"`
}
curiosity := location{-4.5895, 137.4417}
bytes, err := json.Marshal(curiosity)
exitOnError(err)
fmt.Println(string(bytes))
}
// exitOnError prints any errors and exits.
func exitOnError(err error) {
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
小测试
- 为什么在编码JSON数据的时候,Lat和Long字段必须以大写字母开头?
作业题
-
编写一个程序:
- 能够以JSON格式打印出 上面例子中3台 探测器的着陆点。
- 被打印的JSON数据必须包含每个着陆点的名称,并使用上面例子中展示的struct标签特性。
- 请使用json包中的MarshalIndent函数让打印输出变得更加美观和易读。
总结
Go语言中的结构体是组织和管理复杂数据的核心工具,理解其定义、初始化、传递和复制方式对开发高效、可维护的代码至关重要。通过结构体与JSON的结合,我们可以更方便地与外部系统进行数据交换。在本文中,我们不仅展示了如何在Go中定义和使用结构体,还介绍了如何通过结构体标签进行JSON的自定义映射,极大地方便了数据的序列化与反序列化。掌握这些基本技巧,将为你的Go语言编程之路打下坚实的基础。