If you have been paying attention to the design and implementation of Go generic type, you must know that Go generic code implementation is implemented by type parameter (type parameter), which is replaced by type argument (type argument) when running generic code. (unfortunately both parameter and argument are translated into Chinese parameters)
The type parameter also has a type, which is the metadata that describes the behavior of the parameter type, and is called a constraint. The most general constraint is the built-in any
type, which represents an arbitrary type.
In Go generic design, constraints are implemented through interface types ( interface
). Because the interface type is similar to the function black of the constraint, that is, the constraint that qualifies the type argument must implement the type parameter (method set). Of course, in order to achieve the function of generalization, in addition to the method set, Go also used as a constraint to do the extension of the interface, the definition of the concept of type set ( type set
), for example, the following is a constraint on behalf of a type argument can be int, int8, int16, int32 or int64 type, is and ( union
) of the relationship so use the |
notation.
Further, Go also defines the ~ notation, which means that as long as the underlying types are all of a particular type, it’s okay, so the above example can be written in a more generic way
So that instances of type MyInt
defined by type MyInt int
also satisfy this constraint.
constraints package
Go’s current implementation adds a new package, called constraints
, to define built-in constraints, such as the common:
|
|
Even Russ Cox, Ian Lance Taylor, and their proposed and discussed adding the necessary constraints for slice, map, and chan, since they are so commonly used and available in the standard library. (#47203, #47319, 47330#).
Rob Pike recently submitted a new issue, suggesting not to add generic support to the standard library in Go 1.18 #48918. This is a very pertinent suggestion from the guru, suggesting that related cry changes be added to the extensions library first (
x/exp
), and then added to the standard library when mature, which was endorsed by many Gophers. This is another topic.
The package constraints
defines common constraints that can be good for our development, but do you feel a bit unusual?
Omit interface
Yes, according to the Go generic specification, we have to define a constraint before we can use it in generic types and generic methods. Compared to the generic definitions in other languages, do you feel that this has the flavor of being redundant with your pants down?
Look at the definition of Slice, Map, and Chan above, isn’t it redundant? Why can’t we just use ~[]Elem
, ~map[Key]Val
, ~chan Elem
directly in the definition of generic types and methods?
So fzipp proposes that for a non-interface type, the default equivalence is a constraint #48424, which is well described by the following formula.
|
|
In the definition of a generic type, the non-interface type nonInterfaceType
is equivalent to the constraint interface{~nonInterfaceType}
, for example ~int
is equivalent to interface{~int}
. This allows us to omit the constraints
package. This offer was accepted by North and the relevant functionality was added to the go master branch.
mattn’s Go generic example of converting a shaped array to a chan example (which I slightly changed to a more authentic Go writing):
|
|
Here constraints.Chan[E]
is used to represent a generic channel, but now there is an easier way:
Is it convenient to use chan E
directly?
chan E
implicitly stands for interface {chan E}
, which is simpler to use and doesn’t require additional interface (constraint) definitions.
Although Go 1.18 is approaching, I feel that the development work of Go generic is getting heavier and heavier, and there are even some unclear places, so bless it and hope that it will be launched smoothly.