golang通用可选值与结果类型处理插件库valor的使用
Golang通用可选值与结果类型处理插件库valor的使用
介绍
valor模块提供了可选值和结果类型,它们可能包含一个值(因此命名为"valor",是"value or"的缩写)。这不是为了让Go代码看起来不像Go,而是为了将Go已经鼓励的"comma ok"和"errors are values"原则编码化。
安装
go get github.com/phelmkamp/valor
类型
Value
optional.Value
模拟了"comma ok"的习惯用法。它包含一个值(ok)或什么都没有(not ok)。
m := map[string]int{"foo": 42}
val := optional.OfIndex(m, "foo")
fmt.Println(val.IsOk()) // true
var foo int
fmt.Println(val.Ok(&foo), foo) // true 42
valStr := optional.Map(val, strconv.Itoa)
fmt.Println(valStr) // {42 true}
val = optional.OfIndex(m, "bar")
fmt.Println(val.Or(-1)) // -1
fmt.Println(val.OrZero()) // 0
fmt.Println(val.OrElse(func() int { return 1 })) // 1
Result
result.Result
包含一个值或一个错误。
// 传统方式
if res := result.Of(w.Write([]byte("foo"))); res.IsError() {
fmt.Println(res.Error())
return
}
// 尝试获取值,如果不ok则打印包装的错误
// 注意:处理之后只有相关值在作用域内
var n int
if res := result.Of(w.Write([]byte("foo"))); !res.Value().Ok(&n) {
fmt.Println(res.Errorf("Write() failed: %w").Error())
return
}
// 与上面相同,但有多个值
var s string
var b bool
if res := two.TupleResultOf(multi(false)); !res.Value().Do(
func(t two.Tuple[string, bool]) { s, b = t.Values() },
).IsOk() {
fmt.Println(res.Errorf("multi() failed: %w").Error())
return
}
// errors.Is
if res := result.Of(w.Write([]byte("foo"))); res.ErrorIs(io.ErrShortWrite) {
fmt.Println(res.Error())
return
}
// errors.As
if res := result.Of(w.Write([]byte("foo"))); res.IsError() {
var err *fs.PathError
if res.ErrorAs(&err) {
fmt.Println("path=" + err.Path)
}
fmt.Println(res.Error())
return
}
// errors.Unwrap
if res := result.Of(mid(true)); res.IsError() {
fmt.Println(res.ErrorUnwrap().Error())
return
}
Tuples
unit.Type
, singleton.Set
, two.Tuple
, three.Tuple
和four.Tuple
分别包含零到四个值。它们使Value
和Result
能够包含可变数量的值。
get := func(string, int, bool) {
return "a", 1, true
}
val := two.TupleValueOf(get())
fmt.Println(val) // {{a 1} true}
Enum
enum.Enum
是一个枚举类型。它用一组允许的值初始化,然后每个"副本"可选地包含一个当前选择的值。
const (
Clubs = "clubs"
Diamonds = "diamonds"
Hearts = "hearts"
Spades = "spades"
)
var Suit = enum.OfString(Clubs, Diamonds, Hearts, Spades)
func main() {
fmt.Println(Suit.Values()) // [clubs diamonds hearts spades]
fmt.Println(Suit.ValueOf("Foo")) // { false}
fmt.Println(Suit.ValueOf(Hearts)) // {hearts true}
}
其他语言中的类似概念
Rust
Value
类似于Rust的Option
。Result
类似于Rust的Result
。
switch
语句提供了与Rust的match
类似的语义:
var foo int
switch val {
case val.OfOk():
foo = val.MustOk()
fmt.Println("Ok", foo)
case optional.OfNotOk[int]():
fmt.Println("Not Ok")
return
}
var n int
switch res {
case res.OfOk():
n = res.Value().MustOk()
fmt.Println("Ok", n)
case res.OfError():
fmt.Println("Error", res.Error())
return
}
Java
Value
类似于Java的Optional
。
发布
该模块目前处于v0版本,但将尽一切努力避免破坏性更改。相反,功能将根据需要被弃用,并计划在v1中删除。
Linter
valorcheck是一个linter,用于检查对可选值的访问是否针对值不存在的情况进行了保护。
更多关于golang通用可选值与结果类型处理插件库valor的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang通用可选值与结果类型处理插件库valor的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang通用可选值与结果类型处理插件库valor使用指南
valor是一个用于处理可选值和结果类型的Golang库,提供了类似Rust中Option和Result的功能,让错误处理更优雅。
核心概念
valor提供了两种主要类型:
Option[T]
:表示一个可能存在或不存在的值Result[T, E]
:表示一个可能成功或失败的操作
安装
go get github.com/chronos-tachyon/valor
Option类型使用
创建Option
import "github.com/chronos-tachyon/valor"
func main() {
// 有值的Option
someValue := valor.Some(42)
// 无值的Option
noneValue := valor.None[int]()
// 从指针创建
var ptr *int
optFromPtr := valor.FromPtr(ptr) // None
num := 10
optFromPtr2 := valor.FromPtr(&num) // Some(10)
}
操作Option
// 检查是否有值
if someValue.IsSome() {
fmt.Println("有值")
}
// 获取值(不安全)
value := someValue.Unwrap()
// 安全获取值
value, ok := someValue.Get()
// 提供默认值
value := noneValue.UnwrapOr(100)
// 链式操作
result := valor.Some(5).
Map(func(x int) int { return x * 2 }).
Filter(func(x int) bool { return x > 5 }).
UnwrapOr(0)
Result类型使用
创建Result
func divide(a, b int) valor.Result[int, error] {
if b == 0 {
return valor.Error[int](errors.New("除数不能为零"))
}
return valor.OK(a / b)
}
操作Result
res := divide(10, 2)
// 检查是否成功
if res.IsOK() {
fmt.Println("操作成功")
}
// 获取值或错误
value, err := res.Get()
// 安全获取值
value := res.Unwrap()
// 提供默认值
value := res.UnwrapOr(0)
// 错误处理
value := res.UnwrapOrElse(func(err error) int {
log.Printf("错误发生: %v", err)
return 0
})
// 链式操作
result := divide(10, 2).
Map(func(x int) int { return x * 2 }).
AndThen(func(x int) valor.Result[int, error] {
return divide(x, 3)
})
实际应用示例
package main
import (
"errors"
"fmt"
"log"
"github.com/chronos-tachyon/valor"
)
type User struct {
ID int
Name string
}
func findUser(id int) valor.Result[*User, error] {
if id < 0 {
return valor.Error[*User](errors.New("无效的用户ID"))
}
// 模拟数据库查询
if id == 1 {
return valor.OK(&User{ID: 1, Name: "Alice"})
}
return valor.Error[*User](errors.New("用户未找到"))
}
func getUserName(id int) valor.Result[string, error] {
return findUser(id).Map(func(user *User) string {
return user.Name
})
}
func main() {
// 处理成功情况
result := getUserName(1)
if name, err := result.Get(); err == nil {
fmt.Printf("用户名: %s\n", name)
} else {
log.Printf("错误: %v\n", err)
}
// 处理错误情况
result = getUserName(-1)
result.Match(
func(name string) {
fmt.Printf("用户名: %s\n", name)
},
func(err error) {
log.Printf("错误: %v\n", err)
},
)
// 链式操作示例
length := getUserName(1).
Map(func(name string) int {
return len(name)
}).
UnwrapOr(0)
fmt.Printf("名字长度: %d\n", length)
}
优势
- 类型安全:编译时检查,避免运行时错误
- 明确意图:代码清晰表达可能缺失或错误的情况
- 组合操作:支持链式调用,简化复杂逻辑
- 减少if err != nil:更优雅的错误处理方式
valor库特别适合需要明确处理缺失值和错误场景的应用程序,能显著提高代码的可读性和健壮性。