Goptional
Provides a generic Optional[T] type for handling nullable or absent values in a type-safe manner. It is designed for general-purpose use and works with any type T
Features
- Zero Dependencies: No external dependencies, making it lightweight and easy to integrate.
- Type Safety: Generic implementation for any type
T.
- JSON Compatibility: Implements
json.Marshaler and json.Unmarshaler for integration with JSON serialization and deserialization.
- Pointer Avoidance: Uses a struct-based approach to handle optionality without pointers.
- Zero Value Distinction: Clearly distinguishes between zero values (like
0, "", false) and absent values.
- General Purpose: Can be used in any context where you need to represent optional values (it does not need to be JSON-specific).
When to Use Optional vs Pointers
Use Optional[T] instead of *T when:
- You want to avoid nil pointer dereference issues
- You need to distinguish between zero values and absent values
- You want explicit type safety for optional fields
Usage
Installation
go get github.com/eduardolat/goptional
Basic Usage
import "github.com/eduardolat/goptional"
// Create optional values (the direct way)
optionalValue := goptional.Optional[string]{
Value: "hello",
Present: true,
}
// Create optional values using helpers
presentValue := goptional.Some("hello")
absentValue := goptional.None[string]()
// Check presence
if presentValue.Present {
fmt.Println("Value:", presentValue.Value) // Direct access to Value field
}
// Get value or default
defaultValue := absentValue.Or("default")
fmt.Println(defaultValue) // "default"
JSON Serialization
Any absent value is always serialized as null in JSON. This makes it predictable and consistent for API responses.
type User struct {
Name goptional.Optional[string] `json:"name"`
Age goptional.Optional[int] `json:"age"`
Email goptional.Optional[string] `json:"email"`
}
// Unmarshaling JSON with null values
data := `{"name": "John", "age": null, "email": "john@example.com"}`
var user User
json.Unmarshal([]byte(data), &user)
fmt.Println(user.Name.Present) // true
fmt.Println(user.Name.Value) // "John"
fmt.Println(user.Age.Present) // false
fmt.Println(user.Email.Present) // true
fmt.Println(user.Email.Value) // "john@example.com"
// Marshaling back to JSON - absent values become null
jsonData, _ := json.Marshal(user)
// {"name":"John","age":null,"email":"john@example.com"}
Working with Different Types
// Numbers
age := goptional.Some(25)
height := goptional.None[float64]()
// Booleans
isActive := goptional.Some(true)
isVerified := goptional.None[bool]()
// Slices
tags := goptional.Some([]string{"go", "optional"})
emptyTags := goptional.None[[]string]()
// Custom types
type Address struct {
Street string
City string
}
homeAddress := goptional.Some(Address{Street: "123 Main St", City: "Anytown"})
workAddress := goptional.None[Address]()
Method Reference
Constructors
Some[T](value T) Optional[T] - Creates an optional with a present value
None[T]() Optional[T] - Creates an optional with no value (absent)
Value Access
.Or(defaultValue T) T - Returns the value if present, otherwise returns the default
Direct Field Access
.Present bool - Boolean flag indicating if value is present
.Value T - The actual value (zero value of T when Present is false)