I want to write a general equals
method that works as follows:
func equals[T any](a, b T) bool { if hasEqualsMethod(T) { return a.Equals(b) else if isComparable(T) { return a == b } panic("type cannot be compared") }
For this, I created an interface comparable
:
type Comparable[T any] interface { // Equals returns true if the receiver and the argument are equal. Equals(T) bool }
I can check whether the parameter of equals implements this comparable
interface as follows:
func equals[T any](a, b T) bool { aComp, ok := any(a).(Comparable[T]) if ok { return aComp.Equals(b) } ...
However, so far I've found it impossible to find out if a
also satisfies the comparable
constraint and convert it into something that can use ==
.
Is there a way to find out if a generic type T any
is comparable
at runtime and if so, use ==
for comparison ?
I could restrict my entire code to only work with comparable
generic types, but I want the user to be able to manually add the equals
method if their type happens to be something other than comparable
(e.g. because it's based on slicing)).
It is comparable if it is compiled using the equality operator. A type parameter subject to any
is by definition incomparable: it can be virtually anything, including a func() error
.
It is therefore impossible to write equals
functions using static types. You must use reflection or only accept parameters that implement an "equality" interface, such as your own Comparable[T any]
.
With reflection you can use Value#Comparable
:
func equals[T any](a, b T) bool { v := reflect.ValueOf(a) if v.Comparable() { u := reflect.ValueOf(b) return v.Equal(u) } panic("type cannot be compared") }
In this case, using generics might help ensure at compile time that a
and b
have the same exact type, so v.Equal(u)
is not meaningless, instead of declaring equals(a, b any)
.
Using the "equaler" interface, you must provide a named type that implements it in order to convert pre-declared types and call their methods:
func main() { fmt.Println(equals(EqualerFloat64(5.57), EqualerFloat64(5.57))) } type Equaler[T any] interface { Equal(T) bool } type EqualerFloat64 float64 func (f EqualerFloat64) Equal(f2 EqualerFloat64) bool { return f == f2 } func equals[T Equaler[T]](a, b T) bool { return a.Equal(b) }
The above is the detailed content of How to determine if a generic type is 'comparable' at runtime?. For more information, please follow other related articles on the PHP Chinese website!