JSON处理 #
JSON(JavaScript Object Notation)是现代应用中最常用的数据交换格式之一。Go语言通过 encoding/json 包提供了强大的JSON处理能力。
基本编码 #
结构体转JSON #
使用 json.Marshal 将Go值转换为JSON:
go
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Age int
City string
}
func main() {
person := Person{
Name: "张三",
Age: 30,
City: "北京",
}
data, err := json.Marshal(person)
if err != nil {
fmt.Println("编码失败:", err)
return
}
fmt.Println(string(data))
}
格式化输出 #
使用 json.MarshalIndent 生成格式化的JSON:
go
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
City string `json:"city"`
}
func main() {
person := Person{
Name: "张三",
Age: 30,
City: "北京",
}
data, _ := json.MarshalIndent(person, "", " ")
fmt.Println(string(data))
}
输出:
json
{
"name": "张三",
"age": 30,
"city": "北京"
}
结构体标签 #
使用结构体标签控制JSON字段映射:
go
package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email,omitempty"`
Password string `json:"-"`
IsActive bool `json:"is_active"`
}
func main() {
user := User{
ID: 1,
Username: "admin",
Password: "secret123",
IsActive: true,
}
data, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(data))
}
常用标签:
| 标签 | 说明 |
|---|---|
json:"name" |
指定JSON字段名 |
json:"name,omitempty" |
字段为零值时忽略 |
json:"-" |
完全忽略该字段 |
json:",string" |
将数值作为字符串输出 |
基本解码 #
JSON转结构体 #
使用 json.Unmarshal 将JSON转换为Go值:
go
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
City string `json:"city"`
}
func main() {
jsonStr := `{"name":"李四","age":25,"city":"上海"}`
var person Person
err := json.Unmarshal([]byte(jsonStr), &person)
if err != nil {
fmt.Println("解码失败:", err)
return
}
fmt.Printf("%+v\n", person)
}
JSON转map #
当JSON结构不确定时,可以解码到 map[string]interface{}:
go
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonStr := `{
"name": "王五",
"age": 28,
"hobbies": ["读书", "运动"],
"address": {
"city": "广州",
"street": "中山路"
}
}`
var data map[string]interface{}
json.Unmarshal([]byte(jsonStr), &data)
fmt.Println("姓名:", data["name"])
fmt.Println("年龄:", data["age"])
if address, ok := data["address"].(map[string]interface{}); ok {
fmt.Println("城市:", address["city"])
}
}
处理数组 #
JSON数组 #
go
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonStr := `["苹果", "香蕉", "橙子"]`
var fruits []string
json.Unmarshal([]byte(jsonStr), &fruits)
for i, fruit := range fruits {
fmt.Printf("%d: %s\n", i+1, fruit)
}
}
对象数组 #
go
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
Name string `json:"name"`
Price float64 `json:"price"`
}
func main() {
jsonStr := `[
{"name": "笔记本", "price": 5999.00},
{"name": "鼠标", "price": 99.00},
{"name": "键盘", "price": 299.00}
]`
var products []Product
json.Unmarshal([]byte(jsonStr), &products)
var total float64
for _, p := range products {
fmt.Printf("%s: ¥%.2f\n", p.Name, p.Price)
total += p.Price
}
fmt.Printf("总计: ¥%.2f\n", total)
}
流式处理 #
编码到文件 #
go
package main
import (
"encoding/json"
"os"
)
type Config struct {
AppName string `json:"app_name"`
Version string `json:"version"`
Debug bool `json:"debug"`
}
func main() {
config := Config{
AppName: "MyApp",
Version: "1.0.0",
Debug: true,
}
file, _ := os.Create("config.json")
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
encoder.Encode(config)
}
从文件解码 #
go
package main
import (
"encoding/json"
"fmt"
"os"
)
type Config struct {
AppName string `json:"app_name"`
Version string `json:"version"`
Debug bool `json:"debug"`
}
func main() {
file, err := os.Open("config.json")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()
var config Config
decoder := json.NewDecoder(file)
if err := decoder.Decode(&config); err != nil {
fmt.Println("解码失败:", err)
return
}
fmt.Printf("%+v\n", config)
}
自定义编码 #
实现 MarshalJSON #
go
package main
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type Event struct {
Name string
Timestamp time.Time
}
func (e Event) MarshalJSON() ([]byte, error) {
type Alias Event
return json.Marshal(&struct {
Timestamp string `json:"timestamp"`
*Alias
}{
Timestamp: e.Timestamp.Format("2006-01-02 15:04:05"),
Alias: (*Alias)(&e),
})
}
func main() {
event := Event{
Name: "系统启动",
Timestamp: time.Now(),
}
data, _ := json.MarshalIndent(event, "", " ")
fmt.Println(string(data))
}
实现 UnmarshalJSON #
go
package main
import (
"encoding/json"
"fmt"
"strings"
"time"
)
type FlexibleTime struct {
time.Time
}
func (ft *FlexibleTime) UnmarshalJSON(data []byte) error {
str := strings.Trim(string(data), `"`)
layouts := []string{
"2006-01-02",
"2006-01-02 15:04:05",
time.RFC3339,
}
var err error
for _, layout := range layouts {
ft.Time, err = time.Parse(layout, str)
if err == nil {
return nil
}
}
return err
}
func main() {
jsonStr := `"2024-01-15 14:30:00"`
var ft FlexibleTime
json.Unmarshal([]byte(jsonStr), &ft)
fmt.Println("解析时间:", ft.Format("2006年01月02日 15:04"))
}
处理未知结构 #
使用 RawMessage #
go
package main
import (
"encoding/json"
"fmt"
)
type Message struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}
type TextData struct {
Content string `json:"content"`
}
type ImageData struct {
URL string `json:"url"`
Width int `json:"width"`
Height int `json:"height"`
}
func main() {
jsonStr := `{
"type": "text",
"data": {"content": "Hello, World!"}
}`
var msg Message
json.Unmarshal([]byte(jsonStr), &msg)
switch msg.Type {
case "text":
var text TextData
json.Unmarshal(msg.Data, &text)
fmt.Println("文本:", text.Content)
case "image":
var image ImageData
json.Unmarshal(msg.Data, &image)
fmt.Printf("图片: %s (%dx%d)\n", image.URL, image.Width, image.Height)
}
}
实用示例:配置文件处理 #
go
package main
import (
"encoding/json"
"fmt"
"os"
)
type DatabaseConfig struct {
Host string `json:"host"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
Database string `json:"database"`
}
type ServerConfig struct {
Port int `json:"port"`
Host string `json:"host"`
}
type AppConfig struct {
Server ServerConfig `json:"server"`
Database DatabaseConfig `json:"database"`
Debug bool `json:"debug"`
}
func LoadConfig(filename string) (*AppConfig, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
var config AppConfig
decoder := json.NewDecoder(file)
if err := decoder.Decode(&config); err != nil {
return nil, err
}
return &config, nil
}
func SaveConfig(filename string, config *AppConfig) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
return encoder.Encode(config)
}
func main() {
config := &AppConfig{
Server: ServerConfig{
Port: 8080,
Host: "localhost",
},
Database: DatabaseConfig{
Host: "localhost",
Port: 3306,
Username: "root",
Password: "password",
Database: "myapp",
},
Debug: true,
}
SaveConfig("app.json", config)
fmt.Println("配置已保存")
loaded, _ := LoadConfig("app.json")
fmt.Printf("服务器: %s:%d\n", loaded.Server.Host, loaded.Server.Port)
fmt.Printf("数据库: %s@%s:%d/%s\n",
loaded.Database.Username,
loaded.Database.Host,
loaded.Database.Port,
loaded.Database.Database,
)
}
小结 #
| 函数/类型 | 用途 |
|---|---|
json.Marshal |
Go值转JSON字节切片 |
json.Unmarshal |
JSON字节切片转Go值 |
json.MarshalIndent |
格式化JSON输出 |
json.Encoder |
流式JSON编码 |
json.Decoder |
流式JSON解码 |
json.RawMessage |
延迟解码JSON片段 |
| struct tags | 控制字段映射和选项 |
JSON处理是现代应用开发的核心技能,掌握这些技术可以轻松处理API响应、配置文件和数据存储等场景。