I have tried to use generics with Go, but I don't really understand when we use any
or comparable
as type parameter. Can someone help to understand these?

- 34,072
- 23
- 111
- 129

- 81
- 4
2 Answers
It depends on what / how you want to use values of the parameter type. Constraints restrict what you can do with values of those types.
any
is an alias for interface{}
which allows any type. If a parameter can be of any type, that basically won't allow you to do anything with it because you have no guarantee what it will be.
The comparable
constraints only allows types that are comparable, that is, the ==
and !=
operators are allowed to use on values of them. This is good if you want to use the type as a key in a map (maps require key types to be comparable), or if you you want to find an element in a slice, and you want to use the ==
operator to compare the elements to something.
As an example, let's write a generic map-get function:
func get[K comparable, V any](m map[K]V, key K) V {
return m[key]
}
The K
key type must be comparable
, else it cannot be used as the key type of some map (m[K]V
in the example). V
on the other hand shouldn't be constrained, the value type may be anything, and we're not doing anything with it (just returning a value of type V
), so using any
here is the best choice.
Another example, a slice-find function:
func find[V comparable](what V, s []V) int {
for i, v := range s {
if v == what {
return i
}
}
return -1
}
find()
returns the index of the first occurrence of what
in the slice s
, and if it's not in the slice, returns -1
. The type parameter V
here must be comparable
, else you couldn't write v == what
, using V any
would be a compile-time error. The constraint comparable
ensures this find()
function can only be instantiated with types (and called with values) where the ==
operator is defined and allowed.

- 389,944
- 63
- 907
- 827
-
So, `comparable` is good for `map`. I will try that to see what happen there. Btw, Thank @icza for the explanation. – Teguh Mar 18 '22 at 08:16
-
2@Teguh Yes, it's good for map keys, and it's good also for anything where you must use the `==` and/or `!=` operators. – icza Mar 18 '22 at 08:27
The difference between comparable
and any
will change with Go 1.20 (Q1 2023) and (accepted) the proposal "56548: spec: allow basic interface types to instantiate comparable type parameters".
any
will implement the comparable constraint (which it does not before Go 1.20).
Go 1.20-rc1 states:
Comparable types (such as ordinary interfaces) may now satisfy comparable constraints, even if the type arguments are not strictly comparable (comparison may panic at runtime).
This makes it possible to instantiate a type parameter constrained by comparable (e.g., a type parameter for a user-defined generic map key) with a non-strictly comparable type argument such as an interface type, or a composite type containing an interface type.
The principle is:
After substitution, each type argument must satisfy the constraint (instantiated, if necessary) of the corresponding type parameter. Otherwise instantiation fails.
With "satisfy" being:
A type
T
satisfies a constraint interfaceC
if
T
implementsC
; orC
can be written in the forminterface{ comparable; E }
, whereE
is a basic interface andT
is comparable and implementsE
.
Example:
Currently,
any
does not implement the comparable constraint.With the proposed change
any
will be permitted as type argument for comparable:comparable
can be written asinterface{ comparable; E }
and thus the new rule applies, andany
is spec-comparable and implementsE
(whereE
is the empty interface in this case).Currently, the type parameter
P
in the type parameter list[P interface{ comparable; fmt.Stringer }]
cannot be instantiated with the type S
type S struct { data any } func (S) String() string
because
S
is not strictly comparable.
With the proposed change,S
must only be spec-comparable (which it is) and implementfmt.Stringer
(which it does).
("spec-comparable" are for types of comparable operands)
(as opposed to "strictly comparable", which is for the types in comparable
, namely the set of (non-interface) types for which ==
and !=
are defined and for which these operations are guaranteed to not panic)
The implementation as started:

- 1,262,500
- 529
- 4,410
- 5,250
-
*This will change* — what, will change? To be very honest, I don't think this answer should be posted under this question; icza's answer doesn't even mention the strictly comparable limitation. And I don't think it should be posted this early, since the Go specs haven't been amended yet. As of today, you are quoting non-normative references. – blackgreen Dec 02 '22 at 19:03