Golang started to support generic types from version 1.8 start, and I believe many people are in the same wait-and-see state as me. Now that Golang has been released to version 1.19, I think it’s a good idea to give it a try.
Example of adding two numbers together
One of the most common examples of previous calls for Golang to introduce generics is a scenario like adding two numbers together. Taking the example of supporting adding integers and floating point numbers, we need to implement two functions and call them separately before supporting generics.
With generic support, we only need to define a function and directly call.
It can even be further simplified as follows.
Of course, this latter, most simplified version works because it is possible to invert type arguments T
by the types of function arguments v1
, v2
. If there are no parameters, or function parameters can not be deduced from the type is, can not be simplified.
Using Generics in the HTTP API
Although the example of adding two numbers is typical, I usually hardly ever care about it though. After all, in a static language, most of the time the type of the data is already determined and there is no need to really call three functions in the same place.
But when I was wrapping the HTTP API wrapper, I had to wrestle with whether supporting generics would make my code make a little more sense each time.
Specifically, for the common HTTP APIs, the return value is mostly a JSON structured text. This structure is different for each API, but they all usually have some of the same information again, such as error codes and error messages. For example.
|
|
I usually want to be able to easily and uniformly implement the following two features within the API.
- Uniform JSON structure parsing
- Uniform error handling
Not using generics
In the days when there were no generics, we handled this by first initializing the response data structure of the API. Then pass its pointer as a parameter to the function (a common out reference usage). This approach works because json.Encoder.Decode()
itself supports pointers of type any
. Of course, there are some risks. For example, theoretically the caller can exist to pass nil
and other unreasonable use, resulting in code panic.
Also, in order to do uniform error handling, we implement a CheckError
method on the public structure CommonResponse
and define the method as an interface. It is used to constrain the incoming parameters. The advantage of this approach is that it does the most minimal type checking on incoming parameters. But since Golang’s interfaces are not the same as class inheritance, any structure that implements the method but is not a combination of CommonResponse
or CommonResponse
can be used here. There is some risk.
|
|
Using Generic Types
With generic support, we can declare the response data interface, as a type parameter. Then when executing the call, just explicitly specify the type parameter.
This way, in the underlying function, what is passed to the json library is still a pointer of type any
. But this pointer is initialized in this function with an explicit type, so there is no risk of calling an implausible call.
Also, in theory, the type constraints of the generic type T can be directly refined to all API response structure lists. Avoid the problem that any interface that satisfies the CommonResponse.CheckError
function signature can be passed in as a parameter. However, this problem does not have a significant impact, at most, it does not parse reasonable data and does not panic.
|
|
Two comparisons
Purely from the code point of view, in the scenario of HTTP API encapsulation, whether or not to use generics has basically no impact on the amount of code. But in terms of code quality, there is no doubt that generics are relatively more complete.