maybe

package module
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 11, 2025 License: MIT Imports: 9 Imported by: 0

README

maybe - A Go Package for Optionals, Nullables, and Nil-Safe Data Handling

maybe is a Go package providing type-safe optional values and functional programming utilities using Go generics. It helps eliminate nil pointer panics and provides a more expressive way to handle optional values in Go. The package brings modern constructs like Option[T] and Nullable[T] to Go with strong database and JSON integration, along with functional utilities for cleaner data transformation.

Table of Contents

Features

  • Option[T]: Type-safe optional values (Some/None) for any type.
  • Nullable[T]: Optional values specifically designed for database and JSON null values.
  • Functional programming utilities (Map, Filter, Reduce, etc.).
  • JSON marshaling/unmarshaling support.
  • SQL database integration with database/sql compatibility.
  • Zero dependencies beyond the standard library.
  • Fully compatible with Go generics (Go 1.18+).

Why Use maybe?

  • Type Safety: Avoid nil pointer panics and make optional values explicit.
  • Expressiveness: Clearer intent than nil pointers or pointer returns.
  • Composability: Functional utilities for working with collections.
  • Interoperability: Easy conversion between options, nullables, and pointers.
  • Maintainability: More readable code with explicit handling of missing values.
  • Database Integration: First-class support for handling SQL NULL values.
  • JSON Compatibility: Seamless handling of missing or null JSON fields.

Installation

go get github.com/iamNilotpal/maybe

Core Types

Option

Option[T] represents an optional value: either Some(value) or None. It provides a type-safe alternative to nil pointers and helps avoid nil pointer panics. The zero value of Option is None (no value present).

Key operations:

  • Some(value): Create an Option with a value.
  • None[T](): Create an Option with no value.
  • FromPtr(ptr): Convert a pointer to an Option.
  • IsSome(): Check if value is present.
  • IsNone(): Check if value is absent.
  • Value(): Get the value and a success boolean.
  • ValueOr(default): Get the value or a default.
  • Unwrap(): Get the value or panic.
  • Ptr(): Convert to a pointer (nil if None).
Nullable

Nullable[T] represents a value that might be null, designed specifically for handling null values in databases and JSON. Unlike Option[T], which is for general-purpose optional values, Nullable[T] is optimized for scenarios involving external systems that use null values.

Key operations:

  • NullableOf(value): Create a valid Nullable.
  • Null[T](): Create a null Nullable.
  • NullableFromPtr(ptr): Create a Nullable from a pointer.
  • IsNull(): Check if null.
  • IsValid(): Check if not null.
  • Extract(): Get the value and validity.
  • ExtractOr(default): Get the value or a default.
  • ToPtr(): Convert to pointer (nil if null).
  • ToOption(): Convert to Option type.

Usage Examples

Basic Operations
package main

import (
    "fmt"
    "github.com/iamNilotpal/maybe"
)

func main() {
    // Working with Option
    name := maybe.Some("Nilotpal")
    emptyName := maybe.None[string]()

    // Checking value presence
    fmt.Println("Has name:", name.IsSome())        // true
    fmt.Println("Has empty name:", emptyName.IsNone())  // true

    // Safe access patterns
    if value, ok := name.Value(); ok {
        fmt.Println("Name:", value)                // "Nilotpal"
    }

    // Default values
    fmt.Println("Name or default:", name.ValueOr("Anonymous"))           // "Nilotpal"
    fmt.Println("Empty name or default:", emptyName.ValueOr("Anonymous"))  // "Anonymous"

    // Unwrap (safe only when you're certain the value exists)
    fmt.Println("Unwrapped name:", name.Unwrap())  // "Nilotpal"
    // emptyName.Unwrap() would panic with ErrMissingValue

    // Get or set a value
    emptyName.Set("Bob")
    fmt.Println("Name after set:", emptyName.ValueOr(""))  // "Bob"

    emptyName.Unset()
    fmt.Println("Is name none after unset:", emptyName.IsNone())  // true

    // Convert to/from pointers
    // var strPtr *string = name.Ptr()                // Pointer to "Nilotpal"
    // var nilPtr *string = emptyName.Ptr()           // nil pointer

    // someStr := "Hello"
    // optFromPtr := maybe.FromPtr(&someStr)          // Some("Hello")
    // optFromNil := maybe.FromPtr(nilPtr)            // None

    // Working with Nullable (for database/JSON)
    userID := maybe.NullableOf(123)
    noID := maybe.Null[int]()

    fmt.Println("Has ID:", userID.IsValid())       // true
    fmt.Println("No ID:", noID.IsNull())           // true

    // Extract value from Nullable
    if val, ok := userID.Extract(); ok {
        fmt.Println("User ID:", val)               // 123
    }

    // Default values with Nullable
    fmt.Println("ID or default:", userID.ExtractOr(0))     // 123
    fmt.Println("No ID or default:", noID.ExtractOr(999))  // 999

    // Convert between Option and Nullable
    // optionID := userID.ToOption()                  // Some(123)

    // Create Nullable from pointer
    // ptrID := userID.ToPtr()                        // Pointer to 123
    // nullableFromPtr := maybe.NullableFromPtr(ptrID)  // Valid Nullable with 123

    // Using with zero values
    zeroInt := maybe.NullableOf(0)                 // Valid Nullable containing 0
    fmt.Println("Is zero int null?", zeroInt.IsNull())  // false

    // Equality check
    anotherZero := maybe.NullableOf(0)
    fmt.Println("Equal zero values:", zeroInt.Equals(anotherZero))  // true
    fmt.Println("Equal to different value:", zeroInt.Equals(userID))  // false
    fmt.Println("Both null equal:", noID.Equals(maybe.Null[int]()))  // true
}
Working with Functions
package main

import (
    "fmt"
    "github.com/iamNilotpal/maybe"
    "strconv"
)

// A function that may fail
func divide(a, b int) maybe.Option[int] {
    if b == 0 {
        return maybe.None[int]()
    }
    return maybe.Some(a / b)
}

// A function that transforms an option
func double(o maybe.Option[int]) maybe.Option[int] {
    if val, ok := o.Value(); ok {
        return maybe.Some(val * 2)
    }
    return maybe.None[int]()
}

func main() {
    // Chaining operations
    result := divide(10, 2).AndThen(double)
    fmt.Println("10/2*2 =", result.ValueOr(0))  // 10

    // Error propagation
    result = divide(10, 0).AndThen(double)
    fmt.Println("10/0*2 =", result.ValueOr(0))  // 0 (using default)

    // Using default values in chains
    result = maybe.None[int]().AndThenOr(10, double)
    fmt.Println("Default*2 =", result.ValueOr(0))  // 20 (None replaced with 10, then doubled)

    // Parse strings to numbers safely
    parseNumber := func(s string) maybe.Option[int] {
        n, err := strconv.Atoi(s)
        if err != nil {
            return maybe.None[int]()
        }
        return maybe.Some(n)
    }

    fmt.Println("Parsed '42':", parseNumber("42").ValueOr(0))    // 42
    fmt.Println("Parsed 'abc':", parseNumber("abc").ValueOr(0))  // 0 (default)

    // Using TryMap to transform a slice of strings to numbers
    validInputs := []string{"1", "2", "3"}
    validNumbers := maybe.TryMap(validInputs, parseNumber)

    if numbers, ok := validNumbers.Value(); ok {
        fmt.Println("Valid numbers:", numbers)  // [1 2 3]
    }

    invalidInputs := []string{"1", "two", "3"}
    invalidResult := maybe.TryMap(invalidInputs, parseNumber)

    if invalidResult.IsNone() {
        fmt.Println("Failed to parse all inputs")  // This will print
    }
}
Database Integration
package main

import (
    "database/sql"
    "fmt"
    "github.com/iamNilotpal/maybe"
    "time"
    _ "github.com/go-sql-driver/mysql"
)

type User struct {
    ID        int
    Name      string
    Email     maybe.Nullable[string]    // Can be NULL in database
    LastLogin maybe.Nullable[time.Time] // Can be NULL in database
    Age       maybe.Nullable[int]       // Can be NULL in database
}

func main() {
    // Open database connection
    db, err := sql.Open("mysql", "user:password@/dbName")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // Query a user - directly using the Scan method
    user, err := queryUser(db, 1)
    if err != nil {
        panic(err)
    }

    // Use the values
    fmt.Println("User:", user.Name)

    if email, ok := user.Email.Extract(); ok {
        fmt.Println("Email:", email)
    } else {
        fmt.Println("No email provided")
    }

    if login, ok := user.LastLogin.Extract(); ok {
        fmt.Println("Last login:", login.Format(time.RFC1123))
    } else {
        fmt.Println("Never logged in")
    }

    // Update user - directly using the Value method
    err = updateUser(db, user)
    if err != nil {
        panic(err)
    }
}

func queryUser(db *sql.DB, id int) (User, error) {
    var user User

    query := `SELECT id, name, email, last_login, age FROM users WHERE id = ?`
    err := db.QueryRow(query, id).Scan(
        &user.ID,
        &user.Name,
        &user.Email,  // Scan directly into Nullable
        &user.LastLogin,
        &user.Age,
    )

    if err != nil {
        return User{}, err
    }

    return user, nil
}

func updateUser(db *sql.DB, user User) error {
    query := `UPDATE users SET email = ?, last_login = ?, age = ? WHERE id = ?`

    // Value() implements driver.Valuer, so we can pass the Nullable directly
    _, err := db.Exec(query,
        user.Email,     // Value() is called internally
        user.LastLogin, // Value() is called internally
        user.Age,       // Value() is called internally
        user.ID,
    )

    return err
}
JSON Handling
package main

import (
    "encoding/json"
    "fmt"
    "github.com/iamNilotpal/maybe"
)

type Person struct {
    Name     string                 `json:"name"`
    Age      maybe.Option[int]      `json:"age,omitempty"`   // Omitted if not present
    Phone    maybe.Nullable[string] `json:"phone"`           // Explicit null if not present
    Address  maybe.Option[Address]  `json:"address,omitempty"`
}

type Address struct {
    Street  string `json:"street"`
    City    string `json:"city"`
    Country string `json:"country"`
}

func main() {
    // Creating a person with some fields missing
    person := Person{
        Name:  "John Doe",
        Age:   maybe.Some(30),
        Phone: maybe.Null[string](),  // Explicitly null
        // Address is implicitly None
    }

    // Marshal to JSON
    data, _ := json.MarshalIndent(person, "", "  ")
    fmt.Println(string(data))
    // Output:
    // {
    //   "name": "John Doe",
    //   "age": 30,
    //   "phone": null
    // }

    // JSON with explicit null vs missing field
    jsonData := []byte(`{
        "name": "Nilotpal Deka",
        "age": null,
        "phone": "555-1234",
        "address": {
            "street": "123 Main St",
            "city": "Guwahati",
            "country": "IND"
        }
    }`)

    var anotherPerson Person
    json.Unmarshal(jsonData, &anotherPerson)

    // Age was null in JSON, so it's None in our struct
    fmt.Println("Has age:", anotherPerson.Age.IsSome())  // false

    // Phone was present, so it's a valid Nullable
    fmt.Println("Has phone:", anotherPerson.Phone.IsValid())  // true
    if phone, ok := anotherPerson.Phone.Extract(); ok {
        fmt.Println("Phone:", phone)  // "555-1234"
    }

    // Address was present as an object
    if address, ok := anotherPerson.Address.Value(); ok {
        fmt.Println("City:", address.City)  // "Guwahati"
    }

    // Error handling with MarshalJSON
    badJSON := []byte(`{"name": "Bad Data", "phone": ["invalid"]}`)
    var badPerson Person
    err := json.Unmarshal(badJSON, &badPerson)
    if err != nil {
        fmt.Println("JSON error:", err)
    }
}
Functional Programming
package main

import (
    "fmt"
    "github.com/iamNilotpal/maybe"
    "strings"
)

type Product struct {
    ID       int
    Name     string
    Price    float64
    Category string
    InStock  bool
}

func main() {
    products := []Product{
        {1, "Phone", 699.99, "Electronics", true},
        {2, "Laptop", 1299.99, "Electronics", false},
        {3, "Headphones", 149.99, "Audio", true},
        {4, "Monitor", 349.99, "Electronics", true},
        {5, "Speaker", 89.99, "Audio", false},
    }

    // MapSlice: Transform each product to its name
    productNames := maybe.MapSlice(products, func(p Product) string {
        return p.Name
    })
    fmt.Println("Product names:", productNames)
    // Output: [Phone Laptop Headphones Monitor Speaker]

    // FilterSlice: Get products in stock
    inStockProducts := maybe.FilterSlice(products, func(p Product) bool {
        return p.InStock
    })
    fmt.Println("In-stock products count:", len(inStockProducts))  // 3

    // ReduceSlice: Calculate total price of all products
    totalPrice := maybe.ReduceSlice(products, 0.0, func(total float64, p Product) float64 {
        return total + p.Price
    })
    fmt.Println("Total price:", totalPrice)  // 2589.95

    // ForEachSlice: Print each product name with category
    fmt.Println("Products with categories:")
    maybe.ForEachSlice(products, func(p Product) {
        fmt.Printf("- %s (%s)\n", p.Name, p.Category)
    })
    // Output:
    // - Phone (Electronics)
    // - Laptop (Electronics)
    // - Headphones (Audio)
    // - Monitor (Electronics)
    // - Speaker (Audio)

    // Combine operations: Find names of in-stock electronics products in uppercase
    electronicsInStock := maybe.FilterSlice(products, func(p Product) bool {
        return p.Category == "Electronics" && p.InStock
    })

    electronicsNames := maybe.MapSlice(electronicsInStock, func(p Product) string {
        return strings.ToUpper(p.Name)
    })

    fmt.Println("In-stock electronics:", electronicsNames) // [PHONE MONITOR]

    // Working with Options
    optionalProducts := []maybe.Option[Product]{
        maybe.Some(products[0]),
        maybe.None[Product](),
        maybe.Some(products[2]),
    }

    // CollectOptions: Get all valid products, or None if any are missing
    allProducts := maybe.CollectOptions(optionalProducts)
    fmt.Println("All products collected:", allProducts.IsSome()) // false

    // FilterSomeOptions: Get only the valid products, ignoring None
    validProducts := maybe.FilterSomeOptions(optionalProducts)
    fmt.Println("Valid products count:", len(validProducts)) // 2

    // PartitionOptions: Split into valid products and indices of missing products
    validProds, missingIndices := maybe.PartitionOptions(optionalProducts)
    fmt.Println("Valid products:", len(validProds))          // 2
    fmt.Println("Missing product indices:", missingIndices)  // [1]
}
Advanced Usage
package main

import (
    "fmt"
    "github.com/iamNilotpal/maybe"
    "strconv"
)

// Parse a string to an int, returning an Option
func parseToInt(s string) maybe.Option[int] {
    n, err := strconv.Atoi(s)
    if err != nil {
        return maybe.None[int]()
    }
    return maybe.Some(n)
}

// Check if an integer is positive
func ensurePositive(n maybe.Option[int]) maybe.Option[int] {
    if val, ok := n.Value(); ok && val > 0 {
        return maybe.Some(val)
    }
    return maybe.None[int]()
}

// Double a number
func doubleNumber(n maybe.Option[int]) maybe.Option[int] {
    if val, ok := n.Value(); ok {
        return maybe.Some(val * 2)
    }
    return maybe.None[int]()
}

func main() {
    // Chaining operations with AndThen
    result := parseToInt("42").
        AndThen(ensurePositive).
        AndThen(doubleNumber)

    fmt.Println("Result:", result.ValueOr(0)) // 84

    // Chain breaks on first None
    badResult := parseToInt("-10").
        AndThen(ensurePositive). // This returns None
        AndThen(doubleNumber)    // This is not called

    fmt.Println("Bad result:", badResult.ValueOr(0)) // 0

    // Using AndThenOr with default value
    withDefault := maybe.None[int]().
        AndThenOr(5, doubleNumber)

    fmt.Println("With default:", withDefault.ValueOr(0)) // 10

    // TryMap for performing operations that might fail
    inputs := []string{"1", "2", "3"}
    mapped := maybe.TryMap(inputs, parseToInt)

    if numbers, ok := mapped.Value(); ok {
        sum := maybe.ReduceSlice(numbers, 0, func(acc, n int) int {
            return acc + n
        })
        fmt.Println("Sum of valid inputs:", sum) // 6
    }

    // Failing case
    badInputs := []string{"1", "two", "3"}
    badMapped := maybe.TryMap(badInputs, parseToInt)

    fmt.Println("All inputs valid:", badMapped.IsSome()) // false
}
Utility Functions
package main

import (
    "fmt"
    "github.com/iamNilotpal/maybe"
)

type Person struct {
  Name string
  Age  int
}

func main() {
    // IsZero: Check for zero values of different types
    fmt.Println("0 is zero:", maybe.IsZero(0))           // true
    fmt.Println("Empty string is zero:", maybe.IsZero("")) // true
    fmt.Println("42 is zero:", maybe.IsZero(42))         // false
    fmt.Println("Hello is zero:", maybe.IsZero("Hello")) // false

    // Zero value for custom struct
    fmt.Println("Empty struct is zero:", maybe.IsZero(Person{})) // true
    fmt.Println("Non-empty struct is zero:", maybe.IsZero(Person{Name: "Nilotpal"})) // false

    // IsNil: Check for nil values
    var nilMap map[string]int
    var nilSlice []int
    var nilChan chan int
    var nilPtr *int

    fmt.Println("nil map is nil:", maybe.IsNil(nilMap))     // true
    fmt.Println("nil slice is nil:", maybe.IsNil(nilSlice)) // true
    fmt.Println("nil chan is nil:", maybe.IsNil(nilChan))   // true
    fmt.Println("nil ptr is nil:", maybe.IsNil(nilPtr))     // true

    // Non-nil values
    slice := []int{1, 2, 3}
    fmt.Println("Non-empty slice is nil:", maybe.IsNil(slice)) // false

    // Primitive types are never nil
    fmt.Println("Integer is nil:", maybe.IsNil(42)) // false

    // FirstNonZero: Find first non-zero value in a sequence
    value, found := maybe.FirstNonZero(0, "", "fallback", "ignored")
    fmt.Println("First non-zero:", value, found) // "fallback", true

    // All values are zero
    noValue, found := maybe.FirstNonZero(0, "", false, 0.0)
    fmt.Println("No valid value found:", noValue, found) // false, false

    // Complex example with multiple possible sources
    name := ""              // Primary source (empty)
    defaultName := "Guest"  // Default value
    fallbackName := "User"  // Another fallback

    username, _ := maybe.FirstNonZero(name, defaultName, fallbackName)
    fmt.Println("Username:", username) // "Guest"
}

API Reference

Option Methods
  • Some[T](value T) Option[T]: Creates a new Option containing the provided value.
  • None[T]() Option[T]: Creates a new Option with no value.
  • FromPtr[T](ptr *T) Option[T]: Converts a pointer to an Option. Returns Some(value) if pointer is non-nil, or None if pointer is nil.
  • Set(v T): Updates the Option to contain the provided value. Changes None to Some(value) or updates an existing Some value.
  • Unset(): Clears the Option, changing it to None. The contained value is set to the zero value.
  • IsSome() bool: Returns true if the Option contains a value.
  • IsNone() bool: Returns true if the Option does not contain a value.
  • Value() (T, bool): Returns the contained value and a boolean indicating if the value is present.
  • ValueOr(defaultValue T) T: Returns the contained value if present, otherwise returns the provided default value.
  • Ptr() *T: Converts the Option to a pointer. Returns a pointer to the value if Some, or nil if None.
  • Unwrap() T: Returns the contained value if present. Panics with ErrMissingValue if the Option is None.
  • UnwrapOr(defaultValue T) T: Returns the contained value if present, otherwise returns the provided default value.
  • AndThen(fn func(Option[T]) Option[T]) Option[T]: Chains Option operations, executing the provided function only if the Option is Some.
  • AndThenOr(defaultValue T, fn func(Option[T]) Option[T]) Option[T]: Chains Option operations but uses the provided default value if the Option is None.
  • MarshalJSON() ([]byte, error): Marshals the Option to JSON. Returns an error if the Option is None.
  • UnmarshalJSON(data []byte) error: Unmarshal JSON data into the Option, setting it to None if the JSON value is null.
Nullable Methods
  • NullableOf[T](value T) Nullable[T]: Creates a valid Nullable with the provided value.
  • Null[T]() Nullable[T]: Creates an invalid (null) Nullable.
  • NullableFromPtr[T](ptr *T) Nullable[T]: Creates a Nullable from a pointer. If the pointer is nil, returns an invalid Nullable.
  • IsNull() bool: Returns true if this represents a null value.
  • IsValid() bool: Returns true if this represents a non-null value.
  • Extract() (T, bool): Returns the contained value and a boolean indicating if the value is valid.
  • ExtractOr(defaultVal T) T: Returns the value if valid, otherwise returns the default.
  • ToPtr() *T: Converts to a pointer, which will be nil if the value is null.
  • ToOption() Option[T]: Converts Nullable to an Option type.
  • Equals(other Nullable[T]) bool: Compares two Nullable values for equality.
  • MarshalJSON() ([]byte, error): Implements the json.Marshaler interface. An invalid Nullable will be marshaled as null.
  • UnmarshalJSON(data []byte) error: Implements the json.Unmarshaler interface. A null JSON value will be unmarshaled as an invalid Nullable.
  • Value() (driver.Value, error): Implements the driver.Valuer interface for database operations.
  • Scan(value any) error: Implements the sql.Scanner interface for database operations.
Utility Functions Reference
  • IsZero[T comparable](v T) bool: Tests if a value is the zero value for its type.
  • IsNil(i any) bool: Tests if a value is nil. Works with pointer types and handles the case where the interface itself is nil.
  • FirstNonZero[T comparable](vals ...T) (T, bool): Returns the first non-zero value from the provided values.
  • MapSlice[T, U any](input []T, mapFn func(T) U) []U: Applies a function to each element in a slice and returns a new slice with the results.
  • FilterSlice[T any](input []T, predicate func(T) bool) []T: Returns a new slice containing only the elements for which the predicate returns true.
  • ReduceSlice[T, R any](input []T, initial R, reducer func(R, T) R) R: Applies a function to each element in a slice, accumulating a result.
  • ForEachSlice[T any](input []T, fn func(T)): Executes a function for each element in a slice.
  • CollectOptions[T any](options []Option[T]) Option[[]T]: Transforms a slice of Options into an Option containing a slice of all Some values.
  • FilterSomeOptions[T any](options []Option[T]) []T: Returns a slice containing only the values from non-empty Options.
  • PartitionOptions[T any](options []Option[T]) (values []T, noneIndices []int): Separates a slice of Options into values from Some options and indices of None options.
  • TryMap[T, U any](input []T, fn func(T) Option[U]) Option[[]U]: Applies a function that might fail to each element in a slice.

License

MIT License - see LICENSE for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrMissingValue is returned when attempting to access a value that doesn't exist,
	// such as unwrapping a None Option or accessing an invalid Nullable value.
	ErrMissingValue = errors.New("expected a value, but none was present")
)

Functions

func FilterSlice

func FilterSlice[T any](input []T, predicate func(T) bool) []T

FilterSlice returns a new slice containing only the elements for which the predicate returns true. Creates a new slice without modifying the original.

func FilterSomeOptions

func FilterSomeOptions[T any](options []Option[T]) []T

FilterSomeOptions returns a slice containing only the values from non-empty Options. Preserves only the present values, discarding None options.

func FirstNonZero

func FirstNonZero[T comparable](vals ...T) (T, bool)

FirstNonZero returns the first non-zero value from the provided values. If all values are zero, returns the zero value for the type. This is useful for fallback chains where multiple potential values are available.

func ForEachSlice

func ForEachSlice[T any](input []T, fn func(T))

ForEachSlice executes a function for each element in a slice.

func IsNil

func IsNil(i any) bool

IsNil tests if a value is nil. Works with pointer types (pointers, maps, channels, slices, functions) and handles the case where the interface itself is nil.

func IsZero

func IsZero[T comparable](v T) bool

IsZero tests if a value is the zero value for its type. Works with any comparable type (strings, numbers, booleans, etc.).

func MapSlice

func MapSlice[T, U any](input []T, mapFn func(T) U) []U

MapSlice applies a function to each element in a slice and returns a new slice with the results. Transforms elements from type T to type U based on the provided mapping function.

func PartitionOptions

func PartitionOptions[T any](options []Option[T]) (values []T, noneIndices []int)

PartitionOptions separates a slice of Options into two slices

  • One with the values from Some options.
  • One with the indices of None options.

func ReduceSlice

func ReduceSlice[T, R any](input []T, initial R, reducer func(R, T) R) R

ReduceSlice applies a function to each element in a slice, accumulating a result. Combines elements into a single result using the provided reduction function.

Types

type Nullable

type Nullable[T any] struct {
	// contains filtered or unexported fields
}

Nullable[T] represents a value that might be null. Unlike Option, Nullable is specifically designed for handling null values in external systems like databases and JSON APIs. This is particularly useful for database operations where NULL values are common and need distinct handling.

func Null

func Null[T any]() Nullable[T]

Null creates an invalid (null) Nullable.

func NullableFromPtr

func NullableFromPtr[T any](ptr *T) Nullable[T]

NullableFromPtr creates a Nullable from a pointer. If the pointer is nil, returns an invalid Nullable.

func NullableOf

func NullableOf[T any](value T) Nullable[T]

NullableOf creates a valid Nullable with the provided value.

func (Nullable[T]) Equals

func (n Nullable[T]) Equals(other Nullable[T]) bool

Equals compares two Nullable values for equality. Two Nullable values are equal if:

  1. Both are null, or
  2. Both are valid and contain equal values

func (Nullable[T]) Extract

func (n Nullable[T]) Extract() (T, bool)

Value returns the contained value and a boolean indicating if the value is valid. If the Nullable is null, returns the zero value of T and false.

func (Nullable[T]) ExtractOr

func (n Nullable[T]) ExtractOr(defaultVal T) T

ExtractOr returns the value if valid, otherwise returns the default.

func (Nullable[T]) IsNull

func (n Nullable[T]) IsNull() bool

IsNull returns true if this represents a null value.

func (Nullable[T]) IsValid

func (n Nullable[T]) IsValid() bool

IsValid returns true if this represents a non-null value.

func (Nullable[T]) MarshalJSON

func (n Nullable[T]) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface. An invalid Nullable will be marshaled as null.

func (*Nullable[T]) Scan

func (n *Nullable[T]) Scan(value any) error

Scan implements sql.Scanner to convert database values to Go types. This method is used when reading rows from database results.

func (Nullable[T]) ToOption

func (n Nullable[T]) ToOption() Option[T]

ToOption converts Nullable to an Option type. This allows for interoperability between the two optional value representations.

func (Nullable[T]) ToPtr

func (n Nullable[T]) ToPtr() *T

ToPtr converts to a pointer, which will be nil if the value is null.

func (*Nullable[T]) UnmarshalJSON

func (n *Nullable[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface. A null JSON value will be unmarshaled as an invalid Nullable.

func (Nullable[T]) Value

func (n Nullable[T]) Value() (driver.Value, error)

Value implements driver.Valuer to convert Go types to database-compatible values. This method is used when inserting parameters into SQL statements.

type Option

type Option[T any] struct {
	// contains filtered or unexported fields
}

Option[T] represents an optional value: either Some(value) or None. It provides a type-safe alternative to nil pointers and helps avoid nil pointer panics. The zero value of Option is None (no value present).

func CollectOptions

func CollectOptions[T any](options []Option[T]) Option[[]T]

CollectOptions transforms a slice of Options into an Option containing a slice of all Some values. Returns None if any element is None.

func FromPtr

func FromPtr[T any](ptr *T) Option[T]

FromPtr converts a pointer to an Option. Returns Some(value) if the pointer is non-nil, or None if the pointer is nil.

func None

func None[T any]() Option[T]

None creates a new Option with no value. Use this to represent the absence of a value.

func Some

func Some[T any](value T) Option[T]

Some creates a new Option containing the provided value. Use this when you have a definite value to wrap.

func TryMap

func TryMap[T, U any](input []T, fn func(T) Option[U]) Option[[]U]

TryMap applies a function that might fail to each element in a slice. Returns an Option containing the results if all function calls succeed, or None if any call fails.

func (Option[T]) AndThen

func (o Option[T]) AndThen(fn func(Option[T]) Option[T]) Option[T]

AndThen chains Option operations, executing the provided function only if the Option is Some. If the Option is None, returns None without executing the function.

func (Option[T]) AndThenOr

func (o Option[T]) AndThenOr(defaultValue T, fn func(Option[T]) Option[T]) Option[T]

AndThenOr chains Option operations but uses the provided default value if the Option is None. Always executes the function, either with the Option's value or with the default value.

func (Option[T]) IsNone

func (o Option[T]) IsNone() bool

IsNone returns true if the Option does not contain a value.

func (Option[T]) IsSome

func (o Option[T]) IsSome() bool

IsSome returns true if the Option contains a value.

func (Option[T]) MarshalJSON

func (o Option[T]) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface. Attempts to marshal the contained value if present, or returns an error if None.

func (Option[T]) Ptr

func (o Option[T]) Ptr() *T

Ptr converts the Option to a pointer. Returns a pointer to the value if Some, or nil if None.

func (*Option[T]) Set

func (o *Option[T]) Set(v T)

Set updates the Option to contain the provided value. Changes None to Some(value) or updates an existing Some value.

func (*Option[T]) UnmarshalJSON

func (o *Option[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface. Unmarshal JSON data into the Option, setting it to None if the JSON value is null.

func (*Option[T]) Unset

func (o *Option[T]) Unset()

Unset clears the Option, changing it to None. The contained value (if any) is set to the zero value of type T.

func (Option[T]) Unwrap

func (o Option[T]) Unwrap() T

Unwrap returns the contained value if present. Panics with ErrMissingValue if the Option is None. Use this only when you're certain the Option contains a value.

func (Option[T]) UnwrapOr

func (o Option[T]) UnwrapOr(defaultValue T) T

UnwrapOr returns the contained value if present, otherwise returns the provided default value.

func (Option[T]) Value

func (o Option[T]) Value() (T, bool)

Value returns the contained value and a boolean indicating if the value is present. If the Option is None, returns the zero value of T and false.

func (Option[T]) ValueOr

func (o Option[T]) ValueOr(defaultValue T) T

ValueOr returns the contained value if present, otherwise returns the provided default value.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL