golang实现可选结构体字段和变量的插件库optional的使用
Golang 实现可选结构体字段和变量的插件库 optional 的使用
安装
go get github.com/kazhuravlev/optional
快速开始
package main
import (
"encoding/json"
"fmt"
"github.com/kazhuravlev/optional"
)
type User struct {
Name string `json:"name"`
AvatarURL optional.Val[string] `json:"avatar_url,omitempty"`
}
func main() {
// JSON with optional field
data := []byte(`{"name": "Alice", "avatar_url": "https://example.com/avatar.jpg"}`)
var user User
json.Unmarshal(data, &user)
// Check if value exists
if avatarURL, ok := user.AvatarURL.Get(); ok {
fmt.Printf("Avatar URL: %s\n", avatarURL)
}
// Or use a default
url := user.AvatarURL.ValDefault("https://example.com/default.jpg")
fmt.Printf("URL with default: %s\n", url)
}
主要特性
- 类型安全:泛型实现防止运行时类型错误
- 零值友好:不会将缺失值与零值混淆
- 多格式支持:支持 JSON、YAML、SQL 和自定义编组器
- 简单 API:直观的方法如
Get()
、Set()
、HasVal()
和Reset()
API 概览
var opt optional.Val[string]
// Set a value
opt.Set("hello")
// Check and get
if val, ok := opt.Get(); ok {
fmt.Println(val) // "hello"
}
// Get with default
val := opt.ValDefault("default") // "hello"
// Reset to empty
opt.Reset()
// Convert to pointer (nil if empty)
ptr := opt.AsPointer() // *string
完整示例
package main
import (
"encoding/json"
"fmt"
"github.com/kazhuravlev/optional"
)
type Profile struct {
Username string `json:"username"`
Email optional.Val[string] `json:"email"`
Age optional.Val[int] `json:"age"`
IsPremium optional.Val[bool] `json:"is_premium"`
}
func main() {
// 创建带有可选字段的结构体
profile := Profile{
Username: "john_doe",
Email: optional.Set("john@example.com"),
// Age 和 IsPremium 保持未设置状态
}
// 序列化为 JSON
jsonData, _ := json.Marshal(profile)
fmt.Println(string(jsonData))
// 输出: {"username":"john_doe","email":"john@example.com"}
// 反序列化 JSON
var newProfile Profile
json.Unmarshal([]byte(`{"username":"jane_doe","age":30}`), &newProfile)
// 检查可选字段
if age, ok := newProfile.Age.Get(); ok {
fmt.Printf("Age: %d\n", age) // 输出: Age: 30
}
if email, ok := newProfile.Email.Get(); ok {
fmt.Printf("Email: %s\n", email)
} else {
fmt.Println("Email not provided") // 输出: Email not provided
}
// 使用默认值
isPremium := newProfile.IsPremium.ValDefault(false)
fmt.Printf("Is premium: %v\n", isPremium) // 输出: Is premium: false
}
更多关于golang实现可选结构体字段和变量的插件库optional的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现可选结构体字段和变量的插件库optional的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 可选字段与变量:使用 optional 库
在 Go 语言中,由于没有内置的可选字段或变量概念,我们通常需要使用指针或特殊值来表示可选状态。optional
库提供了一种更优雅的方式来处理这种情况。
安装 optional 库
go get github.com/markphelps/optional
基本用法
1. 可选基本类型
package main
import (
"fmt"
"github.com/markphelps/optional"
)
func main() {
// 创建一个有值的可选字符串
strOpt := optional.NewString("hello")
fmt.Println(strOpt.Get()) // 输出: hello true
// 创建一个空的可选字符串
emptyStr := optional.String{}
fmt.Println(emptyStr.Get()) // 输出: false
// 检查是否有值
if strOpt.Present() {
fmt.Println("Value exists:", strOpt.MustGet())
}
// 设置新值
strOpt.Set("world")
fmt.Println(strOpt.MustGet()) // 输出: world
// 清除值
strOpt.Clear()
fmt.Println(strOpt.Present()) // 输出: false
}
2. 可选结构体字段
package main
import (
"fmt"
"github.com/markphelps/optional"
)
type User struct {
ID int
Name string
Email optional.String
Age optional.Uint
Address optional.String
}
func main() {
// 创建用户,部分字段可选
user := User{
ID: 1,
Name: "Alice",
Email: optional.NewString("alice@example.com"),
// Age 和 Address 留空
}
// 检查并获取可选字段
if email, ok := user.Email.Get(); ok {
fmt.Println("Email:", email)
} else {
fmt.Println("Email not provided")
}
// 使用 OrElse 提供默认值
age := user.Age.OrElse(30)
fmt.Println("Age:", age) // 输出: 30
// 更新可选字段
user.Address.Set("123 Main St")
fmt.Println(user.Address.MustGet()) // 输出: 123 Main St
}
3. 高级用法
package main
import (
"fmt"
"github.com/markphelps/optional"
)
func main() {
// 使用 IfPresent 执行回调
opt := optional.NewInt(42)
opt.IfPresent(func(value int) {
fmt.Println("Value is present:", value)
})
// 链式操作
result := optional.NewString(" hello ")
.Map(func(s string) string { return strings.TrimSpace(s) })
.Filter(func(s string) bool { return len(s) > 0 })
.OrElse("default")
fmt.Println(result) // 输出: hello
// 合并两个可选值
opt1 := optional.NewString("first")
opt2 := optional.String{}
merged := optional.FirstPresent(opt1, opt2)
fmt.Println(merged.MustGet()) // 输出: first
}
自定义可选类型
如果需要处理自定义类型,可以这样实现:
package main
import (
"fmt"
"github.com/markphelps/optional"
)
type CustomType struct {
Field1 string
Field2 int
}
func main() {
// 创建自定义类型的可选值
customOpt := optional.New(CustomType{"test", 123})
// 使用自定义类型
if val, ok := customOpt.Get(); ok {
fmt.Printf("Custom value: %+v\n", val)
}
// 或者使用结构体中的可选字段
type Config struct {
Timeout optional.Optional[time.Duration]
Retries optional.Optional[int]
}
cfg := Config{
Timeout: optional.New(5 * time.Second),
}
fmt.Println(cfg.Timeout.OrElse(1 * time.Second)) // 输出: 5s
}
与 JSON 的交互
optional
库还支持 JSON 序列化和反序列化:
package main
import (
"encoding/json"
"fmt"
"github.com/markphelps/optional"
)
type Profile struct {
Name string
Age optional.Int
Website optional.String `json:",omitempty"`
}
func main() {
// 序列化
profile := Profile{
Name: "Bob",
Website: optional.NewString("https://example.com"),
}
data, _ := json.Marshal(profile)
fmt.Println(string(data)) // 输出: {"Name":"Bob","Website":"https://example.com"}
// 反序列化
var p Profile
json.Unmarshal([]byte(`{"Name":"Bob"}`), &p)
fmt.Println(p.Age.Present()) // 输出: false
}
总结
optional
库为 Go 提供了处理可选字段和变量的优雅方式,主要优点包括:
- 更清晰的语义表示可选值
- 避免使用指针带来的 nil 检查
- 提供丰富的操作方法(Map、Filter、IfPresent 等)
- 支持 JSON 序列化/反序列化
- 类型安全,减少运行时错误
对于需要处理可选字段的场景,特别是 API 响应、配置解析等,optional
库是一个很好的选择。