A Rust-inspired declarative-programming and generic-type module for Golang that helps avoid bugs and improve development efficiency.
After using this package, your code style will be like this:
package examples_test
import (
"errors"
"fmt"
"github.com/andeya/gust"
"github.com/andeya/gust/iter"
"github.com/andeya/gust/ret"
)
type Version int8
const (
Version1 Version = iota + 1
Version2
)
func ParseVersion(header iter.Iterator[byte]) gust.Result[Version] {
return ret.AndThen(
header.Next().
OkOr("invalid header length"),
func(b byte) gust.Result[Version] {
switch b {
case 1:
return gust.Ok(Version1)
case 2:
return gust.Ok(Version2)
}
return gust.Err[Version]("invalid version")
},
)
}
func ExampleVersion() {
ParseVersion(iter.FromElements[byte](1, 2, 3, 4)).
Inspect(func(v Version) {
fmt.Printf("working with version: %v\n", v)
}).
InspectErr(func(err error) {
fmt.Printf("error parsing header: %v\n", err)
})
// Output:
// working with version: 1
}
go≥1.19
gust.Result
is a type that represents either a success or an error.gust.Option
is a type that represents either a value or nothing.gust.Mutex
is a better generic-type wrapper forsync.Mutex
that holds a value.gust.RWMutex
is a better generic-type wrapper forsync.RWMutex
that holds a value.gust.SyncMap
is a better generic-type wrapper forsync.Map
.gust.AtomicValue
is a better generic-type wrapper foratomic.Value
.iter
is a package that provides a generic-type iterator.vec
is a package of generic-type functions for slices.valconv
is a package that provides a generic-type value converter.digit
is a package of generic-type functions for digit.- and more...
Improve func() (T,error)
, handle result with chain methods.
- Result Example
func TestResult(t *testing.T) {
var goodResult1 = gust.Ok(10)
var badResult1 = gust.Err[int](10)
// The `IsOk` and `IsErr` methods do what they say.
assert.True(t, goodResult1.IsOk() && !goodResult1.IsErr())
assert.True(t, badResult1.IsErr() && !badResult1.IsOk())
// `map` consumes the `Result` and produces another.
var goodResult2 = goodResult1.Map(func(i int) int { return i + 1 })
var badResult2 = badResult1.Map(func(i int) int { return i - 1 })
// Use `AndThen` to continue the computation.
var goodResult3 = ret.AndThen(goodResult2, func(i int) gust.Result[bool] { return gust.Ok(i == 11) })
// Use `OrElse` to handle the error.
var _ = badResult2.OrElse(func(err error) gust.Result[int] {
fmt.Println(err)
return gust.Ok(20)
})
// Consume the result and return the contents with `Unwrap`.
var _ = goodResult3.Unwrap()
}
Improve func()(T, bool)
and if *U != nil
, handle value with Option
type.
Type [Option
] represents an optional value, and has a number of uses:
- Initial values
- Return values for functions that are not defined over their entire input range (partial functions)
- Return value for otherwise reporting simple errors, where [
None
] is returned on error - Optional struct fields
- Optional function arguments
- Nil-able pointers
- Option Example
func TestOption(t *testing.T) {
var divide = func(numerator, denominator float64) gust.Option[float64] {
if denominator == 0.0 {
return gust.None[float64]()
}
return gust.Some(numerator / denominator)
}
// The return value of the function is an option
divide(2.0, 3.0).
Inspect(func(x float64) {
// Pattern match to retrieve the value
t.Log("Result:", x)
}).
InspectNone(func() {
t.Log("Cannot divide by 0")
})
}
Improve func() error
, handle error with chain methods.
- Errable Example
func ExampleErrable() {
var hasErr = true
var f = func() gust.Errable[int] {
if hasErr {
return gust.ToErrable(1)
}
return gust.NonErrable[int]()
}
var r = f()
fmt.Println(r.IsErr())
fmt.Println(r.UnwrapErr())
fmt.Printf("%#v", r.ToError())
// Output:
// true
// 1
// &gust.errorWithVal{val:1}
}
Feature-rich iterators.
- Iterator Example
func TestAny(t *testing.T) {
var iter = FromVec([]int{1, 2, 3})
if !iter.Any(func(x int) bool {
return x > 1
}) {
t.Error("Any failed")
}
}