Skip to content

高级功能示例 ​

本文提供批量编码、预解析、钩子、高级配置等高级功能的完整示例。

批量编码 ​

EncodeBatch ​

将多个键值对快速编码为 JSON 对象:

go
package main

import (
	"fmt"
	"github.com/cybergodev/json"
)

func main() {
	// 从分散数据构建 JSON
	pairs := map[string]any{
		"id":      1001,
		"name":    "Alice",
		"email":   "[email protected]",
		"active":  true,
		"tags":    []string{"admin", "user"},
		"balance": 1250.50,
	}

	// 使用 EncodeBatch 批量编码为 JSON 对象
	result, err := json.EncodeBatch(pairs)
	if err != nil {
		panic(err)
	}
	fmt.Println(result)

	// 使用 EncodeBatch 搭配 PrettyConfig 格式化输出
	pretty, err := json.EncodeBatch(pairs, json.PrettyConfig())
	if err != nil {
		panic(err)
	}
	fmt.Println(pretty)
}

选择字段编码 ​

EncodeFields ​

只编码结构体的指定字段,适合 API 响应过滤敏感信息:

go
package main

import (
	"fmt"
	"github.com/cybergodev/json"
)

type User struct {
	ID       int    `json:"id"`
	Name     string `json:"name"`
	Email    string `json:"email"`
	Password string `json:"password"`
	Salt     string `json:"salt"`
}

func main() {
	user := User{
		ID:       1,
		Name:     "Alice",
		Email:    "[email protected]",
		Password: "secret123",
		Salt:     "randomsalt",
	}

	// 只编码公开字段(排除敏感信息)
	publicFields := []string{"id", "name", "email"}
	result, err := json.EncodeFields(user, publicFields)
	if err != nil {
		panic(err)
	}
	fmt.Println(result)
	// {"id":1,"name":"Alice","email":"[email protected]"}
}

预解析优化 ​

PreParse ​

预解析 JSON,避免重复解析,提升多次查询性能:

go
package main

import (
	"fmt"
	"github.com/cybergodev/json"
)

func main() {
	// 大型 JSON 数据
	largeJSON := `{
        "users": [
            {"id": 1, "name": "Alice", "email": "[email protected]"},
            {"id": 2, "name": "Bob", "email": "[email protected]"},
            {"id": 3, "name": "Charlie", "email": "[email protected]"}
        ],
        "metadata": {
            "total": 3,
            "page": 1,
            "perPage": 10
        }
    }`

	p, err := json.New()
	if err != nil {
		panic(err)
	}
	defer p.Close()

	// 预解析(只解析一次);用完 Release 释放对解析树的引用
	parsed, err := p.PreParse(largeJSON)
	if err != nil {
		panic(err)
	}
	defer parsed.Release()

	// 多次查询复用预解析结果
	total, _ := p.GetFromParsed(parsed, "metadata.total")
	page, _ := p.GetFromParsed(parsed, "metadata.page")

	// 遍历用户
	for i := 0; i < 3; i++ {
		path := fmt.Sprintf("users.%d.name", i)
		name, _ := p.GetFromParsed(parsed, path)
		fmt.Printf("User %d: %v\n", i, name)
	}

	fmt.Printf("Total: %v, Page: %v\n", total, page)
}

预编译高频路径 ​

CompilePath + GetCompiled ​

PreParse 优化的是「同一份 JSON 查多个路径」;反过来,同一路径要查询大量不同 JSON(如每条请求都取 user.name)时,用 CompilePath 把路径解析结果预编译复用,省掉每次的路径解析开销:

go
package main

import (
	"fmt"
	"github.com/cybergodev/json"
)

func main() {
	p, err := json.New()
	if err != nil {
		panic(err)
	}
	defer p.Close()

	// 模拟持续到达的不同 JSON 文档
	docs := []string{
		`{"user":{"name":"Alice","age":28}}`,
		`{"user":{"name":"Bob","age":34}}`,
		`{"user":{"name":"Carol","age":25}}`,
	}

	// 预编译一次;路径解析结果进入全局编译缓存,用完 Release 归还
	cp, err := p.CompilePath("user.name")
	if err != nil {
		panic(err)
	}
	defer cp.Release()

	for _, doc := range docs {
		name, err := p.GetCompiled(doc, cp)
		if err != nil {
			panic(err)
		}
		fmt.Println("name =", name)
	}
}

// 输出:
// name = Alice
// name = Bob
// name = Carol

与 PreParse 的分工

GetCompiled 每次调用仍执行输入安全校验与 JSON 解析,省掉的只是路径解析环节。两者按热点方向选择:重复查询同一文档 → PreParse;重复使用同一路径 → CompilePath。目前 Set/Delete 暂无 Compiled 变体,预编译路径仅用于查询。

安全获取 ​

SafeGet ​

返回结构化结果,支持链式调用和类型转换:

go
package main

import (
	"fmt"
	"github.com/cybergodev/json"
)

func main() {
	data := `{
        "user": {
            "id": 1001,
            "name": "Alice",
            "age": 28,
            "active": true,
            "balance": 1250.50
        }
    }`

	p, err := json.New()
	if err != nil {
		panic(err)
	}
	defer p.Close()

	// 安全获取单个字段
	nameResult := p.SafeGet(data, "user.name")
	if nameResult.Ok() {
		name, _ := nameResult.AsString()
		fmt.Println("Name:", name)
	}

	// 安全获取并转换类型
	ageResult := p.SafeGet(data, "user.age")
	if ageResult.Ok() {
		age, _ := ageResult.AsInt()
		fmt.Println("Age:", age)
	}

	// 安全获取布尔值
	activeResult := p.SafeGet(data, "user.active")
	if activeResult.Ok() {
		active, _ := activeResult.AsBool()
		fmt.Println("Active:", active)
	}

	// 不存在的路径不会 panic
	emailResult := p.SafeGet(data, "user.email")
	fmt.Println("Email exists:", emailResult.Ok()) // false

	// 使用默认值
	email := emailResult.UnwrapOr("N/A")
	fmt.Println("Email:", email)
}

缓存预热 ​

WarmupCache ​

预热常用路径缓存,提升后续查询性能:

go
package main

import (
	"fmt"
	"github.com/cybergodev/json"
)

func main() {
	// 大型 JSON 数据(模拟)
	largeJSON := `{
        "products": [
            {"id": 1, "name": "Product A", "price": 100},
            {"id": 2, "name": "Product B", "price": 200},
            {"id": 3, "name": "Product C", "price": 300}
        ],
        "categories": ["electronics", "books", "clothing"],
        "settings": {"currency": "USD", "taxRate": 0.1}
    }`

	p, err := json.New()
	if err != nil {
		panic(err)
	}
	defer p.Close()

	// 定义常用路径
	commonPaths := []string{
		"products",
		"products.0.id",
		"products.0.name",
		"products.1.id",
		"products.1.name",
		"categories",
		"settings.currency",
	}

	// 预热缓存
	result, err := p.WarmupCache(largeJSON, commonPaths)
	if err != nil {
		panic(err)
	}

	fmt.Printf("预热完成:%d/%d 成功\n", result.Successful, result.TotalPaths)
	if len(result.FailedPaths) > 0 {
		fmt.Println("失败路径:", result.FailedPaths)
	}

	// 后续查询将使用缓存
	for i := 0; i < 3; i++ {
		path := fmt.Sprintf("products.%d.name", i)
		name := p.GetString(largeJSON, path)
		fmt.Printf("Product %d: %s\n", i, name)
	}
}

批量操作 ​

ProcessBatch ​

批量执行多个操作,提升效率:

go
package main

import (
	"fmt"
	"github.com/cybergodev/json"
)

func main() {
	data := `{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}`

	// 定义批量操作(ID 用于在结果中标识每条操作)
	operations := []json.BatchOperation{
		{ID: "get-name", Type: "get", Path: "users.0.name", JSONStr: data},
		{ID: "get-users", Type: "get", Path: "users", JSONStr: data},
		{ID: "set-name", Type: "set", Path: "users.0.name", Value: "Updated", JSONStr: data},
		{ID: "del-id", Type: "delete", Path: "users.0.id", JSONStr: data},
	}

	// 执行批量操作
	results, err := json.ProcessBatch(operations)
	if err != nil {
		panic(err)
	}

	// 查看结果
	for _, r := range results {
		fmt.Printf("ID: %s\n", r.ID)
		if r.Error != nil {
			fmt.Printf("  错误: %v\n", r.Error)
		} else if r.Result != nil {
			fmt.Printf("  值: %v\n", r.Result)
		}
	}
}

键值内存优化 ​

库内部使用字符串内存池(string interning)自动优化重复键值的内存占用。无需手动管理。

go
package main

import (
	"fmt"
	"github.com/cybergodev/json"
)

func main() {
	// 库在内部自动对重复键值使用内存池
	// 处理大量数据时,重复的字符串键值会自动复用内存
	records := make([]map[string]any, 10000)
	for i := range records {
		records[i] = map[string]any{
			"status": "active",
			"type":   "user",
			"role":   "member",
		}
	}

	// 批量编码时库内部自动优化内存
	result, _ := json.Marshal(map[string]any{
		"status": "active",
		"type":   "user",
	})

	fmt.Println("Sample:", string(result))
}

下一步 ​