With the advent of generics in Go 1.18, developers have pondered the possibility of creating a generic Either[A, B] type. This type would express that a value can either be of type A or B. Situations where such a type would be useful include functions that return one of two possible values (e.g., a normal result or an error).
While the idiomatic approach in Go for error handling is to return both a "normal" value and an error value, some argue that this is semantically incorrect as it implies that the function returns both A and B when the intention is to return either A or B.
Creating a Either type in Go presents a challenge because its interface must include a method that accepts two functions as arguments, one for type A and one for type B. However, Go does not allow interface methods to have type parameters.
To circumvent this restriction, one approach is to borrow the solution from functional programming languages like OCaml. In this solution, we define an Optional type that can represent either a value or nothing (i.e., None). We then define an Either type that wraps two Optional types, one for type A and one for type B.
type Optional[T any] interface { get() (T, error) } type Either[A, B any] interface { is_left() bool is_right() bool find_left() Optional[A] find_right() Optional[B] } type Left[A, B any] struct { data A } type Right[A, B any] struct { data B }
The Either interface defines methods to determine whether the value is a Left (type A) or a Right (type B) and retrieve the wrapped Optional type. The Left and Right structs implement these methods to represent the different cases.
Here is an example of how to use the Either type:
import ( "fmt" "os" ) func main() { var e1 Either[int, string] = left[int, string](4143) var e2 Either[int, string] = right[int, string]("G4143") fmt.Println(e1) fmt.Println(e2) if e1.is_left() { if l, err := e1.find_left().get(); err == nil { fmt.Printf("The int is: %d\n", l) } else { fmt.Fprintln(os.Stderr, err) } } if e2.is_right() { if r, err := e2.find_right().get(); err == nil { fmt.Printf("The string is: %s\n", r) } else { fmt.Fprintln(os.Stderr, err) } } }
In this example, we create two Either values: e1 which is a Left containing an integer and e2 which is a Right containing a string. We demonstrate how to pattern-match on the Either values using the is_left() and is_right() methods to access the underlying values and handle them accordingly.
The above is the detailed content of How Can We Implement a Generic Either Type in Go to Handle Either/Or Return Values?. For more information, please follow other related articles on the PHP Chinese website!