In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article focuses on "how to understand Go generic and non-generic code". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let the editor take you to learn how to understand Go generic and non-generic code.
Catalogue
1. Turn on generics
two。 No generic code and generic code
2.1. AddSlice
2.2. Constrained StringConstraint with method
1. Turn on generics
In the Go1.17 version, you can do this by:
Export GOFLAGS= "- gcflags=-G=3"
Or when compiling and running the program, add:
Go run-gcflags=-G=3 main.go2. No generic code and generic code 2.1. AddSlice
First of all, look at the code that does not have generics:
Package main import ("fmt") func AddIntSlice (input [] int, diff int) [] int {output: = make ([] int, 0, len (input)) for _, item: = range input {output = append (output, item+diff)} return output} func AddStrSlice (input [] string, diff string) [] string {output: = make ([] string, 0, len (input)) for _, item: = range input {output = append (output) Item+diff)} return output} func main () {intSlice: = [] int {1,2,3,4,5,6} fmt.Printf ("intSlice [% + v] + 2 = [% + v]\ n", intSlice, AddIntSlice (intSlice, 2)) strSlice: = [] string {"hi,", "hello,", "bye,"} fmt.Printf ("strSlice [% + v] + man = [% + v]\ n", strSlice, AddStrSlice (strSlice) "man")} / / output / / intSlice [[1 2 3 4 56]] + 2 = [3 4 5 6 7 8] / / strSlice [[hi, hello, bye,]] + man = [[hi,man hello,man bye,man]]
In the code that does not use generics above, for intSlice and strSlice, you need to construct two functions to deal with them; and if there are subsequent types such as float64, uint32, and so on, you need more Add...Slice functions.
If you use generics, these Add...Slice functions can be merged into a single function, in which you can add types that can use the + operator (whether it's mathematical addition or string concatenation).
The generic code is as follows:
Package main import ("fmt") type PlusConstraint interface {type int, string} func AddSlice [T PlusConstraint] (input [] T, diff T) [] T {output: = make ([] T, 0, len (input)) for _, item: = range input {output = append (output, item+diff)} return output} func main () {intSlice: = [] int {1,2,3,4 5} fmt.Printf ("intSlice [% + v] + 2 = [% v]\ n", intSlice, AddSlice (intSlice, 2)) strSlice: = [] string {"hi,"hello,", "bye,"} fmt.Printf ("strSlice [% v] + man = [% v]\ n", strSlice, AddSlice (strSlice, "man"))} / output / / intSlice [[1 2 3 4 5]] + 2 = [3 4 5 6 7]] / strSlice [hi [hi] Hello, bye,] + man = [[hi,man hello,man bye,man]]
Is it super simple, but the concept of constraint, PlusConstraint, is introduced into the AddSlice function. In the square brackets of AddSlice is the type parameter, T is the formal parameter of this type parameter, and the following PlusConstraint is the constraint of T, which means that only T types that meet the constraints can be used in this function.
The parameters in parentheses after AddSlice are regular parameters, also known as untyped parameters, which can be replaced by T without specifying a specific type (int, string, etc.).
In AddSlice, for the T-type value item, it performs the + operation of item and diff, which may be a mathematical accumulation or a concatenation of strings.
So now you may have to ask, does the T type have to support the + operator? is it possible that it is a struct?
The answer is: no.
As mentioned earlier, only T that meets the constraint can be used in AddSlice, and the constraint is the PlusConstraint above.
PlusConstraint is defined in the same way as an interface type, except that there is an extra line inside:
Type int, string
That is to say, only two types, int and string, satisfy this constraint, and the concept of type set is involved here, which will be mentioned later.
Therefore, with this constraint, both the parameters input and diff passed into AddSlice can use the + operator. If you want to add float46, uint64 and other types to your AddSlice function, you can add these two types to PlusConstraint.
In the above code, only two basic types, int and string, are constrained. In actual development, we may define our own types:
Type MyInt int type MyStr string
Can it be compiled if you use these two types in AddSlice? The answer is yes. In a generic draft, this situation cannot be compiled, and ~ int | ~ string needs to be added to the constraint, indicating that the underlying type is int or string. In Go1.17, the above PlusConstraint includes int, string, and types with both as the underlying types.
Package main import ("fmt") type MyInt int type MyStr string type PlusConstraint interface {type int, string} func AddSlice [T PlusConstraint] (input [] T, diff T) [] T {output: = make ([] T, 0, len (input)) for _, item: = range input {output = append (output, item+diff)} return output} func main () {intSlice: = [] MyInt {1,2,3,4 5} fmt.Printf ("intSlice [% + v] + 2 = [% v]\ n", intSlice, AddSlice (intSlice, 2)) strSlice: = [] MyStr {"hi,"hello,", "bye,"} fmt.Printf ("strSlice [% v] + man = [% v]\ n", strSlice, AddSlice (strSlice, "man"))} / output / / intSlice [[1 2 3 4 5]] + 2 = [3 4 5 6 7]] / strSlice [hi [hi] Hello, bye,] + man = [[hi,man hello,man bye,man]] 2.2. Constrained StringConstraint with method
As mentioned earlier, the definition of a constraint is very similar to an interface, so if there is a method in the constraint, isn't that the proper interface?
There is a difference between the two:
The only members of an interface are methods and embedded interface types
Members of constraints include methods, embedded constraint types, types (int, string, etc.)
Take a look at the following example of not using generics:
Package main import ("fmt") func ConvertSliceToStrSlice (input [] fmt.Stringer) [] string {output: = make ([] string, 0, len (input)) for _, item: = range input {output = append (output, item.String ()} return output} type MyInt int func (mi MyInt) String () string {return fmt.Sprintf ("[% d] th", mi)} func ConvertIntSliceToStrSlice (input [] MyInt) [] string {output: = make ([] string, 0) Len (input) for _, item: = range input {output = append (output, item.String ())} return output} type MyStr string func (ms MyStr) String () string {return string (ms) + "!!"} func ConvertStrSliceToStrSlice (input [] MyStr) [] string {output: = make ([] string, 0, len (input) for _, item: = range input {output = append (output) Item.String ()} return output} func main () {intSlice: = [] MyInt {1,2,3,4} / / compile error, [] MyInt not match [] fmt.Stringer / / fmt.Printf ("% v convert% v", intSlice, ConvertSliceToStrSlice (intSlice)) fmt.Printf ("% v convertIntToStr% v\ n", intSlice, ConvertIntSliceToStrSlice (intSlice)) strSlice: = [] MyStr {"111"," 222" "333"} fmt.Printf ("% v convertStrToStr% v\ n", strSlice, ConvertStrSliceToStrSlice (strSlice)) / / output / / [[1] th [2] th [3] th [4] th] convertIntToStr [[1] th [2] th [3] th [4] th] / / [111customers! 222boxes! 333 stories!] ConvertStrToStr [111!!! 222!!! 333!!!]}
In the above code, both MyInt and MyStr implement the fmt.Stringer interface, but neither of them can call the ConvertSliceToStrSlice function because its input parameter is of type [] fmt.Stringer, and [] MyInt does not match it, which will report an error when compiling. If we want to convert [] MyInt to [] string, we need to define a function whose input parameter is [] MyInt. For example, for [] MyStr, we need another function.. It is obvious that both have achieved fmt.Stringer, and in theory they should both be able to pass ConvertSliceToStrSlice, which is too anti-human.
Haha, generics achieve this function.
Package main import ("fmt") type StringConstraint interface {String () string} func ConvertSliceToStrSlice [T StringConstraint] (input [] T) [] string {output: = make ([] string, 0, len (input)) for _, item: = range input {output = append (output, item.String ())} return output} type MyInt int func (mi MyInt) String () string {return fmt.Sprintf ("[% d] th" Mi)} type MyStr string func (ms MyStr) String () string {return string (ms) + "!!"} func main () {intSlice: = [] MyInt {1,2,3,4} / / compile error, [] MyInt not match [] fmt.Stringer fmt.Printf ("% v convert% v\ n", intSlice, ConvertSliceToStrSlice (intSlice)) strSlice: = [] MyStr {"111"," 222", "333"} fmt.Printf ("% v convert% v\ n" StrSlice, ConvertSliceToStrSlice (strSlice) / [[1] th [2] th [3] th [4] th] convert [[1] th [2] th [3] th [4] th] / / [111 stories! 222 cycles! 333 stories!] Convert [111!!! 222!!! 333!!!]}
To keep it simple, define a String () string in the StringConstraint constraint, so that as long as there is a type of this method, it can be used in ConvertSliceToStrSlice as T. Under this constraint, all types with the String () string method can be converted, but if we want to make the constraint more stringent, for example, only types with the underlying type int or string can call this function. Then we can further add constraints to StringConstraint:
Type StringConstraint interface {type int, string String () string}
So the set of types that satisfy this constraint is that the underlying type is int or string, and has the String () string method. And this type set is the intersection of the type set of type int, string and the type set of String () string. The follow-up introduction of specific concepts.
In this way, MyFloat and MyUint cannot call the function ConvertSliceToStrSlice.
Package main import ("fmt") type StringConstraint interface {type int, string String () string} func ConvertSliceToStrSlice [T StringConstraint] (input [] T) [] string {output: = make ([] string, 0, len (input)) for _, item: = range input {output = append (output, item.String ())} return output} type MyFloat float64 func (mf MyFloat) String () string {return fmt.Sprintf ("% fth" Mf)} type MyInt int func (mi MyInt) String () string {return fmt.Sprintf ("[% d] th", mi)} type MyStr string func (ms MyStr) String () string {return string (ms) + "!!"} func main () {intSlice: = [] MyInt {1,2,3,4} / / compile error, [] MyInt not match [] fmt.Stringer fmt.Printf ("% v convert% v\ n", intSlice ConvertSliceToStrSlice (intSlice)) strSlice: = [] MyStr {"111"," 222,333 "} fmt.Printf ("% v convert% v\ n ", strSlice, ConvertSliceToStrSlice (strSlice)) / / output / / [[1] th [2] th [3] th [4] th] convert [[1] th [2] th [3] th [4] th] / [111 percent! 222 percent! 333 percent!] Convert [111!!! 222!!! 333!!!] FloatSlice: = [] MyFloat {1.1,2.2,3.3} / / type checking failed for main / / prog.go2:48:44: MyFloat does not satisfy StringConstraint (MyFloat or float64 not found in int, string) fmt.Printf ("% v convert% v\ n", floatSlice, ConvertSliceToStrSlice (floatSlice))} so far, I believe you have a deeper understanding of "how to understand Go generic and non-generic code". You might as well do it! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.