golang零分配可空结构体转换与编解码插件库nan的使用

Golang零分配可空结构体转换与编解码插件库nan的使用

简介

nan是一个零分配的Nullable结构体库,提供方便的转换函数和各种编解码器支持。

主要特性:

  • 短名称"nan"
  • 方便的转换函数
  • 可选择需要的编解码器,减少依赖
  • 可以将自定义结构体转换为nan兼容类型

支持的类型

  • bool
  • float32/float64
  • int/int8/int16/int32/int64
  • string
  • time.Time
  • uint/uint8/uint16/uint32/uint64

支持的编解码器

  • 标准JSON
  • encoding.TextMarshaler/TextUnmarshaler
  • jsoniter
  • easyjson
  • go-json
  • Scylla和Cassandra(兼容gocql)
  • SQL

使用示例

package main

import (
	"encoding/json"
	"fmt"
	"github.com/kak-tus/nan"
)

func main() {
	// 定义包含Nullable字段的结构体
	var data struct {
		Code nan.NullString `json:"code"`
	}

	// 编码为JSON(值为null)
	b, err := json.Marshal(data)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(b)) // 输出: {"code":null}

	// 设置值
	data.Code = nan.String("1")
	// 等同于: data.Code = nan.NullString{String: "1", Valid: true}

	// 再次编码
	b, err = json.Marshal(data)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(b)) // 输出: {"code":"1"}

	// 从指针设置值
	code := "2"
	data.Code = nan.StringAddr(&code)

	b, err = json.Marshal(data)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(b)) // 输出: {"code":"2"}

	// 从nan获取值
	codeVal := data.Code.String
	fmt.Println(codeVal) // 输出: 2

	// 从nan获取指针
	codeAddr := data.Code.Addr()
	fmt.Println(*codeAddr) // 输出: 2
}

辅助函数

nan提供了一些辅助函数来简化代码:

// 传统方式
val := true
addr := &val

// 使用nan更简洁
addr := nan.Bool(true).Addr()

生成编解码器

你可以选择只生成需要的编解码器,而不是依赖整个库:

# 安装nan工具
go install github.com/kak-tus/nan/cmd/nan@latest

# 生成JSON和jsoniter编解码器
nan gen -json -jsoniter

这会生成只包含指定编解码器的文件。

自定义结构体转换

假设你有自定义结构体:

type MyStruct struct {
	ID   int
	Name string
}

使用nan工具生成对应的Nullable版本:

nan extra -json -jsoniter example/structs.go

这会生成*_nan.go文件,包含Nullable版本和编解码器。

使用示例:

var val MyStruct

nullVal := NanMyStruct(val)
// 等同于: nullVal := NullMyStruct{MyStruct: val, Valid: true}

fmt.Println(nullVal.ID)

性能

nan库设计为零分配,性能优异。具体benchmark数据可以参考项目文档。

与sqlc集成

nan可以与sqlc很好地集成,具体集成方式可以参考项目文档。


更多关于golang零分配可空结构体转换与编解码插件库nan的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang零分配可空结构体转换与编解码插件库nan的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang零分配可空结构体转换与编解码插件库nan

nan是一个专门用于处理可空值的Golang库,它提供了零分配的方式在基本类型和其可空版本之间进行转换,同时支持JSON编解码。

主要特性

  1. 零分配转换:在基本类型和可空类型之间转换不产生内存分配
  2. 支持所有基本类型的可空版本
  3. 内置JSON编解码支持
  4. 简洁易用的API

安装

go get github.com/kak-tus/nan

基本使用示例

基本类型转换

package main

import (
	"fmt"
	"github.com/kak-tus/nan"
)

func main() {
	// 从普通int创建可空int
	var nullableInt nan.NullInt64
	nullableInt.Set(42) // 设置值
	fmt.Println(nullableInt) // 输出: {42 true}

	// 检查是否有值
	if nullableInt.Valid {
		fmt.Println("Value:", nullableInt.Int64) // 输出: Value: 42
	}

	// 重置为null
	nullableInt.Reset()
	fmt.Println(nullableInt) // 输出: {0 false}

	// 从普通值创建
	fromInt := nan.Int64(10)
	fmt.Println(fromInt) // 输出: {10 true}

	// 转换为普通值(带默认值)
	val := nullableInt.Or(100)
	fmt.Println(val) // 输出: 100 (因为nullableInt现在是null)
}

JSON编解码

package main

import (
	"encoding/json"
	"fmt"
	"github.com/kak-tus/nan"
)

type User struct {
	ID      nan.NullInt64  `json:"id"`
	Name    nan.NullString `json:"name"`
	Age     nan.NullInt32  `json:"age,omitempty"`
	Active  nan.NullBool   `json:"active"`
}

func main() {
	// JSON解码
	jsonStr := `{"id":123,"name":"Alice","active":true}`
	var user User
	err := json.Unmarshal([]byte(jsonStr), &user)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", user)
	// 输出: {ID:{Int64:123 Valid:true} Name:{String:Alice Valid:true} Age:{Int32:0 Valid:false} Active:{Bool:true Valid:true}}

	// JSON编码
	user.Age.Set(25)
	jsonData, err := json.Marshal(user)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(jsonData))
	// 输出: {"id":123,"name":"Alice","age":25,"active":true}
}

支持的类型

nan库支持以下可空类型:

  • NullBool
  • NullFloat32, NullFloat64
  • NullInt, NullInt8, NullInt16, NullInt32, NullInt64
  • NullString
  • NullTime
  • NullUint, NullUint8, NullUint16, NullUint32, NullUint64

高级用法

自定义JSON字段名

type Product struct {
	ID      nan.NullInt64  `json:"product_id"`
	Name    nan.NullString `json:"product_name"`
	Price   nan.NullFloat64 `json:"price,omitempty"`
}

链式调用

value := nan.NullString{}.
	Set("hello").
	Or("default value")

数据库扫描支持

nan类型实现了sql.Scanner接口,可以直接用于数据库查询结果的扫描:

var id nan.NullInt64
err := db.QueryRow("SELECT id FROM users WHERE username = ?", "alice").Scan(&id)
if err != nil {
	// 处理错误
}
if id.Valid {
	fmt.Println("User ID:", id.Int64)
}

性能考虑

nan库通过以下方式优化性能:

  1. 零分配转换:基本类型和可空类型之间的转换不产生堆分配
  2. 避免反射:使用类型特定的方法而不是反射
  3. 最小化内存占用:每个可空类型只包含原始类型和一个bool标志

与标准库的比较

相比于标准库的sql.NullXXX类型:

  1. 更全面的类型支持(包括各种大小的整数和浮点数)
  2. 更一致的API设计
  3. 更好的JSON支持
  4. 更简洁的代码

总结

nan库为Golang提供了处理可空值的优雅解决方案,特别适合需要处理JSON或数据库交互的场景。它的零分配特性和全面的类型支持使其成为处理可选字段的理想选择。

回到顶部