On the moment of writing generics in Golang (v1.26) are not very flexible, however you can implement something which almost feels like true Java.
Implementation
If you continue to extend this interface to make it even more java-like, you’ll quickly bump into current language limitations, however even this is enough to make the code more elegant.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
type Result[T any] struct { value T err error } func Ok[T any](v T) Result[T] { return Result[T]{value: v} } func Err[T any](e error) Result[T] { return Result[T]{err: e} } func (r Result[T]) IsPresent() bool { return r.err == nil } func (r Result[T]) IsEmpty() bool { return r.err != nil } func (r Result[T]) Get() (T, error) { return r.value, r.err } func (r Result[T]) Map(fn func(T) T) Result[T] { if r.err != nil { return r } return Ok(fn(r.value)) } |
Usage example
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package main import ( "errors" "fmt" "strings" ) func main() { optionalUser := loadUser(0) if optionalUser.IsPresent() { user, _ := optionalUser.Get() println("User:", user.Name) } else { _, err := optionalUser.Get() println("Error:", err.Error()) } u, _ := loadUser(1). Map(func(user User) User { user.Name = "Mr. " + user.Name return user }). Map(func(user User) User { user.Name = strings.ToUpper(user.Name) return user }). Get() fmt.Println(u.Name) // MR. JOHN DOE } func loadUser(id int) Result[User] { if id == 0 { return Err[User](errors.New("user not found")) } return Ok(User{ID: id, Name: "John Doe"}) } type User struct { ID int Name string } |