Moving every success value to the heap seems like a big loss to me but I don't see an alternative. I think going the interface route also ends up wrapping everything in an even fatter pointer. But at least I get to think "ah maybe this isn't going to get boxed and it will be free".
interface Result[T] {
IsOk(): bool
IsErr(): bool
Unwrap(): T
UnwrapError(): error
}
// Ok is a Result that represents a successful operation.
struct Ok[T] {
Value: T
}
func Ok[T](value T) Result[T] {
return Ok[T]{Value: value}
}
func (s Ok[T]) IsOk() bool {
return true
}
func (s Ok[T]) IsErr() bool {
return false
}
func (s Ok[T]) Unwrap() T {
return s.Value
}
func (s Ok[T]) UnwrapError() error {
panic("UnwrapError called on Ok")
}
// Err is a Result that represents a failed operation.
struct Err[T] {
Reason: error
}
func Err[T](reason error) Result[T] {
return Err[T]{Reason: reason}
}
func (e Err[T]) Error() string {
return e.Reason.Error()
}
func (e Err[T]) IsOk() bool {
return false
}
func (e Err[T]) IsErr() bool {
return true
}
func (e Err[T]) Unwrap() T {
panic(fmt.Errorf("Unwrap called on Err: %w", e.Reason))
}
func (e Err[T]) UnwrapError() error {
return e.Reason
}