Loading...
Loading...
Compare original and translation side by side
ultrathinkultrathinkgo get github.com/samber/mogo get github.com/samber/mo| Type | Purpose | Think of it as... |
|---|---|---|
| Value that may be absent | Rust's |
| Operation that may fail | Rust's |
| Value of one of two types | Scala's |
| Value of one of X types | Scala's |
| Async value not yet available | JavaScript |
| Lazy synchronous side effect | Haskell's |
| Lazy async computation | fp-ts |
| Stateful computation | Haskell's |
| 类型 | 用途 | 可以类比为... |
|---|---|---|
| 可能不存在的值 | Rust的 |
| 可能失败的操作 | Rust的 |
| 两种类型之一的值 | Scala的 |
| X种类型之一的值 | Scala的 |
| 尚未就绪的异步值 | JavaScript的 |
| 惰性同步副作用 | Haskell的 |
| 惰性异步计算 | fp-ts的 |
| 带状态的计算 | Haskell的 |
SomeNoneimport "github.com/samber/mo"
name := mo.Some("Alice") // Option[string] with value
empty := mo.None[string]() // Option[string] without value
fromPtr := mo.PointerToOption(ptr) // nil pointer -> None
// Safe extraction
name.OrElse("Anonymous") // "Alice"
empty.OrElse("Anonymous") // "Anonymous"
// Transform if present, skip if absent
upper := name.Map(func(s string) (string, bool) {
return strings.ToUpper(s), true
})SomeNoneGetMustGetOrElseOrEmptyMapFlatMapMatchForEachToPointerIsPresentIsAbsentjson.Marshaler/Unmarshalersql.Scannerdriver.ValuerSomeNoneimport "github.com/samber/mo"
name := mo.Some("Alice") // 带值的Option[string]
empty := mo.None[string]() // 无值的Option[string]
fromPtr := mo.PointerToOption(ptr) // 空指针转换为None
// 安全提取值
name.OrElse("Anonymous") // "Alice"
empty.OrElse("Anonymous") // "Anonymous"
// 仅当值存在时转换,不存在则跳过
upper := name.Map(func(s string) (string, bool) {
return strings.ToUpper(s), true
})SomeNoneGetMustGetOrElseOrEmptyMapFlatMapMatchForEachToPointerIsPresentIsAbsentjson.Marshaler/Unmarshalersql.Scannerdriver.ValuerOkErrEither[error, T]// Wrap Go's (value, error) pattern
result := mo.TupleToResult(os.ReadFile("config.yaml"))
// Same-type transform — errors short-circuit automatically
upper := mo.Ok("hello").Map(func(s string) (string, error) {
return strings.ToUpper(s), nil
})
// Ok("HELLO")
// Extract with fallback
val := upper.OrElse("default").Map.FlatMapResult[T].MapResult[T]Result[U]Result[[]byte]Result[Config]mo.Doimport "github.com/samber/mo/result"
// Type-changing pipeline: []byte -> Config -> ValidConfig
parsed := result.Pipe2(
mo.TupleToResult(os.ReadFile("config.yaml")),
result.Map(func(data []byte) Config { return parseConfig(data) }),
result.FlatMap(func(cfg Config) mo.Result[ValidConfig] { return validate(cfg) }),
)OkErrErrfTupleToResultTryGetMustGetOrElseMapFlatMapMapErrMatchForEachToEitherIsOkIsErrorOkErrEither[error, T]// 包装Go的(value, error)模式
result := mo.TupleToResult(os.ReadFile("config.yaml"))
// 同类型转换——错误会自动短路处理
upper := mo.Ok("hello").Map(func(s string) (string, error) {
return strings.ToUpper(s), nil
})
// 结果为Ok("HELLO")
// 带回退的提取
val := upper.OrElse("default").Map.FlatMapResult[T].MapResult[T]Result[U]Result[[]byte]Result[Config]mo.Doimport "github.com/samber/mo/result"
// 类型转换管道:[]byte -> Config -> ValidConfig
parsed := result.Pipe2(
mo.TupleToResult(os.ReadFile("config.yaml")),
result.Map(func(data []byte) Config { return parseConfig(data) }),
result.FlatMap(func(cfg Config) mo.Result[ValidConfig] { return validate(cfg) }),
)OkErrErrfTupleToResultTryGetMustGetOrElseMapFlatMapMapErrMatchForEachToEitherIsOkIsError// API that returns either cached data or fresh data
func fetchUser(id string) mo.Either[CachedUser, FreshUser] {
if cached, ok := cache.Get(id); ok {
return mo.Left[CachedUser, FreshUser](cached)
}
return mo.Right[CachedUser, FreshUser](db.Fetch(id))
}
// Pattern match
result.Match(
func(cached CachedUser) mo.Either[CachedUser, FreshUser] { /* use cached */ },
func(fresh FreshUser) mo.Either[CachedUser, FreshUser] { /* use fresh */ },
)Result[T]Either[L, R]Either3[T1, T2, T3]Either4Either5// 返回缓存数据或新鲜数据的API
func fetchUser(id string) mo.Either[CachedUser, FreshUser] {
if cached, ok := cache.Get(id); ok {
return mo.Left[CachedUser, FreshUser](cached)
}
return mo.Right[CachedUser, FreshUser](db.Fetch(id))
}
// 模式匹配
result.Match(
func(cached CachedUser) mo.Either[CachedUser, FreshUser] { /* 使用缓存数据 */ },
func(fresh FreshUser) mo.Either[CachedUser, FreshUser] { /* 使用新鲜数据 */ },
)Result[T]Either[L, R]Either3[T1, T2, T3]Either4Either5mo.DoResultMustGet()result := mo.Do(func() int {
// MustGet panics on None/Err — Do catches it as Result error
a := mo.Some(21).MustGet()
b := mo.Ok(2).MustGet()
return a * b // 42
})
// result is Ok(42)
result := mo.Do(func() int {
val := mo.None[int]().MustGet() // panics
return val
})
// result is Err("no such element")mo.DoResultMustGet()result := mo.Do(func() int {
// MustGet在None/Err时会恐慌——Do会将其捕获为Result错误
a := mo.Some(21).MustGet()
b := mo.Ok(2).MustGet()
return a * b // 42
})
// result为Ok(42)
result := mo.Do(func() int {
val := mo.None[int]().MustGet() // 引发恐慌
return val
})
// result为Err("no such element").Map.FlatMapopt := mo.Some(42)
doubled := opt.Map(func(v int) (int, bool) {
return v * 2, true
}) // Option[int]option.Mapresult.Mapimport "github.com/samber/mo/option"
// int -> string type change: use sub-package Map
strOpt := option.Map(func(v int) string {
return fmt.Sprintf("value: %d", v)
})(mo.Some(42)) // Option[string]option.Pipe3result.Pipe3import "github.com/samber/mo/option"
result := option.Pipe3(
mo.Some(42),
option.Map(func(v int) string { return strconv.Itoa(v) }),
option.Map(func(s string) []byte { return []byte(s) }),
option.FlatMap(func(b []byte) mo.Option[string] {
if len(b) > 0 { return mo.Some(string(b)) }
return mo.None[string]()
}),
).Map.FlatMapopt := mo.Some(42)
doubled := opt.Map(func(v int) (int, bool) {
return v * 2, true
}) // Option[int]option.Mapresult.Mapimport "github.com/samber/mo/option"
// int -> string类型转换:使用子包的Map
strOpt := option.Map(func(v int) string {
return fmt.Sprintf("value: %d", v)
})(mo.Some(42)) // Option[string]option.Pipe3result.Pipe3import "github.com/samber/mo/option"
result := option.Pipe3(
mo.Some(42),
option.Map(func(v int) string { return strconv.Itoa(v) }),
option.Map(func(s string) []byte { return []byte(s) }),
option.FlatMap(func(b []byte) mo.Option[string] {
if len(b) > 0 { return mo.Some(string(b)) }
return mo.None[string]()
}),
)type UserResponse struct {
Name string `json:"name"`
Nickname mo.Option[string] `json:"nickname"` // omits null gracefully
Bio mo.Option[string] `json:"bio"`
}type UserResponse struct {
Name string `json:"name"`
Nickname mo.Option[string] `json:"nickname"` // 优雅地忽略null
Bio mo.Option[string] `json:"bio"`
}type User struct {
ID int
Email string
Phone mo.Option[string] // implements sql.Scanner + driver.Valuer
}
err := row.Scan(&u.ID, &u.Email, &u.Phone)type User struct {
ID int
Email string
Phone mo.Option[string] // 实现了sql.Scanner + driver.Valuer
}
err := row.Scan(&u.ID, &u.Email, &u.Phone)// Convert map lookup to Option
func MapGet[K comparable, V any](m map[K]V, key K) mo.Option[V] {
return mo.TupleToOption(m[key]) // m[key] returns (V, bool)
}// 将map查找转换为Option
func MapGet[K comparable, V any](m map[K]V, key K) mo.Option[V] {
return mo.TupleToOption(m[key]) // m[key]返回(V, bool)
}mo.FoldFoldablestr := mo.Fold[error, int, string](
mo.Ok(42), // works with Option, Result, or Either
func(v int) string { return fmt.Sprintf("got %d", v) },
func(err error) string { return "failed" },
)
// "got 42"mo.FoldFoldablestr := mo.Fold[error, int, string](
mo.Ok(42), // 适用于Option、Result或Either
func(v int) string { return fmt.Sprintf("got %d", v) },
func(err error) string { return "failed" },
)
// "got 42"OrElseMustGetMustGetmo.DoTupleToResult(T, error)Result[T]MapFlatMapResult[T]Either[L, R]Option[string]stringresult.Map(...).FlatMap(...).OrElse(default)option.Pipe3(...)OrElseMustGetMustGetmo.DoTupleToResult(T, error)Result[T]MapFlatMapResult[T]Either[L, R]Option[string]stringresult.Map(...).FlatMap(...).OrElse(default)option.Pipe3(...)samber/cc-skills-golang@golang-samber-losamber/cc-skills-golang@golang-error-handlingsamber/cc-skills-golang@golang-safetysamber/cc-skills-golang@golang-databasesamber/cc-skills-golang@golang-design-patternssamber/cc-skills-golang@golang-samber-losamber/cc-skills-golang@golang-error-handlingsamber/cc-skills-golang@golang-safetysamber/cc-skills-golang@golang-databasesamber/cc-skills-golang@golang-design-patterns