Several changes worth noting in Go 1.18

Permalink to this article – https://ift.tt/skny1Ku

Since March 23, I have been working from home for 20+ days. During this period, I should have had time to write this review article, but after being blocked for two days, things like grabbing vegetables and bringing children began to bother me. I really have no intention of writing this article. The lockdown was finally lifted on April 13. The weather after going to work was different, and people became more energetic, so this article was also put on the agenda. I hope the new crown epidemic will end soon, and I hope everyone can enjoy the warmth of that spring day in the sunny outdoors.

On March 15, 2022, the Go team officially announced the release of the official version of Go 1.18 on the official blog. The Internet celebrity version of Go 1.18 has finally landed. The addition of generics makes Go 1.18 another milestone version after Go 1.0 (the first official version) , Go 1.5 (implementing bootstrapping, removing C code, new GC) , and Go 1.11 (introducing Go module) .

Generics is the biggest change in syntax features since the Go language was open sourced, and its changes and impacts are huge. Despite the efforts of the Go core team, the release of the official version of Go 1.18 was delayed by a month. But the good news is that Go 1.18 with the addition of generic syntax continues to maintain Go1 compatibility , which in itself is a victory for the Go team, and also for the Go community.

Compared with the previous version, Go 1.18 has changed a lot and has slightly more bugs . Fortunately, a month after the release, all the hustle and bustle has been quiet. At the time of writing, Go 1.18.1 has been released with many bug fixes, including some related to Go generics.

Let’s take a look at the noteworthy changes in Go 1.18. The version I use here is Go 1.18.1.

Let’s start with generics.


1. Go syntax changes

1. Generics: the most complex Go syntax feature in history

In the past, when Go released a major version, the content of the Go syntax change column was always very small, or even a single stroke because there was no change.

What’s more, there are only a handful of syntax changes from Go 1.0 to Go 1.17:

We have seen that in the past ten years, Go has only changed a few of the above at the pure syntax level. And the complexity of generics introduced in Go 1.18 is enough to exceed the sum of the syntactic changes in the above versions. In the face of the newly added generic features, even Gopher, who has many years of Go programming experience, will have a feeling of “secondary learning” . This is because Go generics are the most complex, difficult to read and understand syntax features since the birth of Go . Of course, the complexity of generics is not only valid for Go language, but also for other programming languages ​​with generic syntax features. It is also the most complex syntax. Aspirants can challenge the generics of C++: template. There is also the brain-burning Andrei Alexandrescu’s “C++ Design New Thinking: Application of Generic Programming and Design Patterns” , the English title is “Modern C++ Design: Generic Programming and Design Patterns Applied” .

Also because of the complexity of generics, the Go team in the Go 1.18 release notes reserves the right to break programs compiled against Go 1.18 in future releases by fixing the Go generics bug. Of course the Go team also promises to minimize any such damage as much as possible, but there is no guarantee that such damage will be zero.

In addition, the generic implementation of Go 1.18 is not a complete version, and there are many constraints on usage. These constraints will most likely be phased out in subsequent Go versions. And the implementation in Go 1.18 is different from the design document of Type Parameter Proposal . Go official recommends that the specification of the Go language prevail.

2. The main syntax points of generics

As mentioned earlier, Go generics are the biggest change at the syntax level since Go became open source. The last version of the technical proposal for Go generics is dozens of pages long. into a booklet. In this overview article, I will only briefly describe the main syntax points of Go generics. In future articles, we will go deeper into the syntax details of generics and analyze them one by one.

The main grammatical points about Go generics are actually mentioned in the “Introduction to Go Generics” of the Go official blog:

Generics add three important new additions to the Go language:

  • Functions and types add support for type parameters .
  • Defines an interface type as a collection of types, including interface types without methods.
  • Type deduction is supported, and in most cases, type arguments can be omitted when calling a generic function.

Let’s take a look at them separately.

type parameter

A type parameter is a declared (unqualified) type name in a function declaration, in the receiver section of a method declaration, or in the type parameter list of a type definition. A type parameter acts as a placeholder for an unknown type in the declaration, and is replaced by a type argument when a generic function or generic type is instantiated.

In order to give you a better understanding of how type parameters are declared and what they do, let’s take functions as an example to compare the parameters of ordinary functions with the type parameters of generic functions:

We know that the parameter list of a normal function is like this:

 func Foo(x, y aType, z anotherType)

Here, x, y, z are the names of the parameters, that is, variables, and aType, anotherType are the types of the parameters, that is, types.

Let’s take another look at the list of type parameters for generic functions:

 func GenericFoo[P aConstraint, Q anotherConstraint](x,y P, z Q)

Here, P and Q are the names of the type parameters, that is, the type. aConstraint and anotherConstraint represent the constraints of the type parameters, which we can understand as a limitation on the optional values ​​of the type parameters.

What modifies type parameters in a type parameter list is a constraint. So what are constraints? Let’s continue reading.

constraints

Constraints specify conditions that a type argument must satisfy. A type is a valid type argument for the type parameter modified by a constraint if it satisfies all the conditions specified by the constraint.

In Go generics, we use the interface type to define constraints . To this end, the definition of Go interface types is also extended, and we can declare both a collection of methods for the interface, and a list of types that can be used as type arguments.

The following is an example of constraint definition and usage:

 type C1 interface { ~int | ~int32 M1() } type T struct{} func (T) M1() { } type T1 int func (T1) M1() { } func foo[P C1](t P)() { } func main() { var t1 T1 foo(t1) var t T foo(t) // 编译器报错:T does not implement C1 }

In this code, C1 is the constraint we defined, which declares a method M1, and two types (~int | ~int32) that can be used as type arguments. We see that multiple type argument types in the type list are separated by “|”.

In this code, we also define two custom types T and T1, both of which implement the M1 method, but the underlying type of the T type is struct{}, and the underlying type of the T1 type is int, so that As a result, although the T type satisfies the method set of the constraint C1, the type T does not satisfy the constraint C1 because the underlying type is not int or int32, which will also cause the foo(t) call to report an error at the compilation stage. However, I would also recommend that you define the interface types for constraints and interface types for traditional interfaces separately, unless the constraint type really needs both a method set and a type list.

To make this extension to interface types better understood, Go introduces type sets to explain it all. There is an illustration of type set in “Introduction to Go Generics” , so I won’t repeat it here. You can click the link to read it step by step.

Type instantiation and type inference

As in the above example, the main function’s call to foo(t1) takes advantage of the two features of type reification and type deduction.

foo is a generic function whose function declaration has a type parameter P constrained by C1, and the process of initializing P with the type parameter T1 is type reification. But you also noticed that we did not use: foo[T1](t1), but omitted the explicit initialization of P and used foo(t1) directly, which is the convenience brought by Go type deduction. The Go compiler will automatically deduce the type argument based on the type of the incoming argument. Automatic type inference allows people to use a more natural style when writing code that calls generic functions.

generic type

In addition to functions that can carry type parameters and become “generic functions”, types can also have type parameters and become “generic types”. For example, the following code defines a vector generic type:

 type Vector[T any] []T

This is a type definition with type parameters that follow the type name, again enclosed in square brackets. Parameter names (such as T) in the type parameter list can be referenced in the type definition body. Type parameters also have their own constraints, such as any in the above code.

In Go 1.18, any is an alias for interface{}, which is also a predefined identifier, using any as a constraint on the type parameter, which means there is no constraint. For a note on how to use any and how to use any, please move to my previous article “The first thing after switching to Go 1.18: replace all interface{} with any” .

Here is the definition of another generic type:

 type Tree[T interface{}] struct { left, right *Tree[T] value T } func (t *Tree[T]) Lookup(x T) *Tree[T] { ... } var stringTree Tree[string]

In the above example, the generic type Tree stores the value of the type parameter T. Generic types can also have methods, such as Lookup in this example. In order to use a generic type, it must be instantiated, e.g. Tree[string] is an example of instantiating a Tree with the type argument string.

Shortcomings of Current Generic Implementations

The impact of generics on Go projects is various, and it is indeed difficult to implement all the features of generics in one version iteration cycle. Therefore, the current implementation of Go generics in Go 1.18 is incomplete and has limitations. According to the Go 1.18 release notes, the limitations include the following:

  • The Go compiler cannot handle type declarations in generic functions or methods, and the Go team hopes to provide support for this feature in a future release.
 func GenericsFoo[T any](s T) T { type bar int // type declarations inside generic functions are not currently supported var a bar println(a) return s }
  • The Go compiler does not support the predefined functions real, imag and complex to handle generic type arguments. The Go team hopes to remove this restriction in a future release.
 package main import ( "golang.org/x/exp/constraints" ) func GenericsFoo[T constraints.Complex](s T) T { n := real(s) // s (variable of type T constrained by constraints.Complex) not supported as argument to real for go1.18 (see issue #50937 println(n) i := complex(s, s) // invalid argument: arguments have type T, expected floating-point _ = i return s } func main() { var i = complex(1.0, 2.0) // 1+2i GenericsFoo(i) }
  • The Go compiler only supports calling method m on a value x of parameter type P, provided that m must be explicitly declared by P’s constraint interface. Likewise, method valuex.m and method expression Pm are only supported if P explicitly declares m. Even if all types in the set of types P implement m, calling m on x is not supported if m is not explicitly declared. The Go team hopes to remove this limitation in a future release.
 package main type C interface { T | T1 // T和T1都实现了M1方法} func GenericsFoo[PC](p P) { p.M1() // p.M1 undefined (type P has no field or method M1) } type T struct{} func (T) M1() {} type T1 struct{} func (T1) M1() {} func main() { GenericsFoo(T{}) }
  • The Go compiler does not currently support accessing a struct field xf, where x is the type parameter type, even if all types in the type parameter’s type set have a field f. The Go team may lift this restriction in a future release.
 package main type C interface { T | T1 // T和T1的类型定义中都包含名为Name的字段} func GenericsFoo[PC](p P) { _ = p.Name // p.Name undefined (type P has no field or method Name) } type T struct { Name string } type T1 struct { Name string } func main() { GenericsFoo(T{}) }
  • Currently the Go compiler does not allow embedded fields (unnamed fields) of type parameters or pointers to type parameters as struct types. Likewise, embedding a type parameter in an interface type is not allowed. The Go team is currently unsure if these restrictions will be lifted in future releases.
 package main type F[T any, P any] struct { Name string *T //embedded field type cannot be a (pointer to a) type parameter P // embedded field type cannot be a (pointer to a) type parameter } type MyInterface interface{} type GenericsInterface[I MyInterface] interface { M1() I // cannot embed a type parameter } func main() { var f F[string, string] _ = f }
  • The Go compiler does not support including an interface type with a non-empty method set in a union type definition that contains more than 1 type element. Whether this will be allowed in future versions, the Go team is currently unsure.
 package main type MyInterface interface { M1() } type GenericsInterface interface { ~int | MyInterface | float64 // cannot use main.MyInterface in union (main.MyInterface contains methods) } func main() { }

Another popular concern is that type parameters are not supported in method declarations of ordinary types:

 package main type F struct{} func (F) M1[T any](t T){} // syntax error: method must have no type parameters func main() { var f F[string] f.M1("hello") }

However, this is not an implementation-level limitation, but the Go Generics Technical Draft is so determined. It is uncertain whether the use of type parameters in methods will be supported in the future. However, the above problem can be “mitigated” by generic types with type parameters.

Generic types can have their own methods. In the method declaration of the generic type, the receiver uses the same type parameter as the type declaration. This type parameter can also be used in the normal parameter list of the method, as shown in the following example:

 package main type F[T any] struct{} func (F[T]) M1(t T) {} // ok func main() { var f F[string] f.M1("hello") }
Officially maintained generics package

Go 1.18 arguably provides only a minimal version of Go generics, in addition to the syntax, plus two predefined types: comparable and any. The generic packages of constraints, slices and maps that were originally intended to be added to the standard library were temporarily shelved due to a comment from Go’s old father Rob Pike . Rob Pike’s reason is very simple. Go generics are the biggest language change since the birth of Go. Go 1.18 version carries too many changes and is prone to errors. And the Go core development team has no experience in using the new generics. He suggested that the Go core development team should wait, observe and learn more, not to take too big steps, and Go should move steadily at its own pace .

So the three packages mentioned above are placed under golang.org/x/exp:

 golang.org/x/exp/constraints golang.org/x/exp/slices golang.org/x/exp/maps

When the time is right, these packages will enter the Go standard library just like the http2 packages back then.

Go toolchain support for generic syntax

After Go Generics was released, the tools on the Go toolchain officially maintained by Go have basically determined the plan to support the generic syntax. By the time Go 1.18 was released, gofmt/goimports, go vet, gopls (supported from v0.8.1) all implemented support for generics.

However, except gofmt is released with the Go installation package, other tools need to be installed and upgraded to the latest version by themselves. Otherwise, your editor will give various error messages once you use generic syntax or new predefined identifiers like any, comparable, etc.

If you use vim+vim-go+goimports+gopls like me , then if you want the editor to support go 1.18, you can use the following command to upgrade the tool version to support go 1.18 generics:

 $go install golang.org/x/tools/cmd/goimports@latest $go install golang.org/x/tools/gopls@latest

Of course, there are still many tools in the Go community that have not caught up in time, and this will give the Go community some time.

Regarding the details and implementation principles of Go generic syntax, I will gradually explain it in subsequent articles.

After talking about the tome of generics, let’s take a look at the changes between the Go compiler and the Go module.

2. Go compiler and Go module changes

1. Fixed syntax bugs

We know that after declaring a variable inside a Go function, if it is not used, the Go compiler will report an error. But before Go 1.18, the Go compiler will not report an error for the variable p in the following example , even if it is not used in main.

This was fixed in Go 1.18, and if the example was compiled with Go 1.18, a compiler error in the comments would appear.

 package main func main() { p := true // go 1.18会报错:p declared but not used,但Go 1.18之前的版本不会。 func() { p = true }() }

At the same time, gopls and go vet will also give error prompts for the above problems.

2. Introduce architectural level on AMD64 platform

As we all know, the Go language still has a lot of room for improvement in the optimization of the target code. In the Go 1.18 version, Go introduced an optimization measure, that is , the concept of architectural level was introduced on the AMD64 platform . The higher the level, the newer the available instructions, and the performance of the compiled code using the new instructions may be improved to some extent.

Go 1.18 uses the GOAMD64 environment variable to indicate the level adopted by the compiler, and the v1 version is used by default. This release uses instructions supported by all x86-64 CPUs in production code. To put it bluntly, it is to use the most basic instructions, with good compatibility, but the performance is also the worst.

The other three candidate values ​​for the GOAMD64 environment variable are v2, v3, v4. Higher versions are less compatible, but performance may be improved by using new instructions.

  • GOAMD64=v2: all v1 instructions, plus CMPXCHG16B, LAHF, SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3;
  • GOAMD64=v3: all v2 instructions, plus AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, OSXSAVE;
  • GOAMD64=v4: All v3 instructions, plus AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL.

On the road of optimization, the Go team has been working hard, and the Go compiler can now inline functions with range loops or loop statements with labels.

3. Enriched SBOM information

Over the years, security issues about the software supply chain have frequently occurred, and the software supply chain has become a hot spot in the field of IT security. As the head development language of cloud-native platforms, middleware and services, Go’s own security and the security of the built software have become critical. Go’s investment in security is also gradually increasing, and the means are gradually increasing and enriching. SBOM (Software Bill of Materials) is an important protection method to mitigate software supply chain attacks. Go has provided relevant support in version 1.13. In Go version 1.18, Go has enriched the SBOM information provided. For details on this, please refer to the previous Article: “Talking about Software Supply Chain Security in Go” .

4. Negative effects of Go generics on the compiler

The introduction of Go generics increases the expressiveness of the Go language, but it also has a negative impact on the Go compiler, the biggest of which is the compilation speed. According to the Go 1.18 release notes, the compilation speed of Go 1.18 is 15% slower than that of Go 1.17, and even if you don’t use generic syntax in your code at all, this performance drop is there. So this is also the problem that the Go team will focus on solving in Go 1.19 .

5. go module changes

Since Go 1.16 , Go modules have entered a mature stage. However, there are still some minor issues that need to be fixed, one of which is which commands go.mod and go.sum have the right to modify. Go 1.18 clarified that there are only three commands that can modify go.mod and go.sum: go get, go mod tidy and go mod download. In this way, developers can safely execute other commands provided by the go toolchain in the project root directory.

6. Introduce Go workspace (workspace)

The introduction of the Go module has greatly improved Go package dependencies and build problems. However, there are still two problems that lead to poor experience in the process of software collaborative development of Go module, and these two problems are difficult to be fundamentally solved under the original go module mechanism. The two questions are:

  • Modify the dependency package by yourself and build it based on the locally modified dependency package;
  • Depends on a local unpublished module.

The original go module replace mechanism has poor experience in the case of collaboration, which brings a certain extra mental burden to developers. So Go developer Michael Matloob proposed a proposal called “Multi-Module Workspaces in cmd/go” in April 2021. This proposal introduces a go.work file to enable Go workspace mode. go.work sets some local paths through the use indicator. The go modules in these paths constitute a workspace. Go commands can operate the go modules in these paths, and the go modules in the workspace will be used preferentially . At the same time, go.work is related to the local environment and does not need to be submitted to the code repository. Each developer can have their own go.work file according to their own development environment settings.

Regarding the Go workspace mechanism, I introduced it in detail in the article “Go 1.18 New Features Preview: Go Workspace Mode” , you can go to that article and read it carefully. However, that article was written before the release of Go 1.18 beta1. At that time, some go.work content, such as the directory indicator, has changed in the official version of Go 1.18. Everyone should pay attention to this.

After reading the compiler, let’s briefly talk about other toolchains.

3. Go toolchain changes

1. go fuzzing

The biggest change on the Go toolchain side is the introduction of native support for fuzzing. Fuzzing, also known as fuzz testing, is called fuzz testing or random testing in Chinese. It is essentially an automated testing technique, or more specifically, an automated testing technique based on random input, which is often used to find bugs and problems in code that processes user input.

In terms of specific implementation, Fuzzing does not need to use pre-defined data sets as program input like unit testing, but will construct some random data by itself through the data construction engine or based on the initial data provided by developers, and provide it as input to Our program then monitors the program for panics, assertion failures, infinite loops, etc. These constructed random data are called corpus . In addition, fuzz testing is not a one-time test. If the number of executions and execution time are not limited, fuzz testing will continue to be executed, so it is also a continuous testing technology.

Go 1.18 incorporates fuzz testing into the go test tool chain, and together with unit testing and performance benchmarking (https://ift.tt/sgvdixb), it has become an important part of the Go native testing tool chain member.

The test cases of go fuzzing test are placed in xx_test.go like ordinary test cases (TestXxx), performance benchmark tests (BenchmarkXxx), etc., but the function name style corresponding to the test case is changed to FuzzXxx. A simple Fuzzing test case is as follows:

 func FuzzXxx(f *testing.F) { // 设置种子语料(可选) // 执行Fuzzing f.Fuzz(func(t *testing.T, b []byte) { //... ... }) }

Regarding the Go Fuzzing test, I have a very comprehensive and systematic description in “Go 1.18 New Features Preview: Native Support for Fuzzing Test” , you can go to that article to read and understand.

What needs to be paid extra attention here is that although the Fuzzing test is very similar to the unit test and benchmark test in writing, it is also very simple, but the Fuzzing test runs continuously and will not stop, so it is just like the Go 1.18 release notes. That way: Fuzzing tests can consume a lot of memory and may affect your machine performance when running. Also note that at runtime, the fuzzing engine will write the expanded test range values ​​to the fuzzing cache directory inside \$GOCACHE/fuzz. There is currently no limit on the number of files or total bytes written to the obfuscated cache, so it can take up a lot of storage space (maybe several GB or more). Therefore, it is recommended to find a special high-end machine to run the fuzzing test.

2. go get

In the Go module construction mode, go get returns to its own work, focusing on obtaining the go module and the corresponding dependent modules. Compilation and installation are no longer performed. In this way, go install, which was originally deprived of the halo by go get, regained its own functions in module-aware mode: installing modules and executable files of the specified version or latest version.

Finally, let’s look at some other small changes.

4. Other minor changes

1. gofmt supports concurrency

“gofmt’s code style is not someone’s favorite, it’s everyone’s favorite”. The gofmt code style has become a consensus among Go developers and has been integrated into the development culture of the Go language. Go 1.18 brings gofmt, which supports concurrency, to Go developers. Undoubtedly, its biggest advantage is speed. Especially on multi-core CPUs, gofmt can use more computing power to quickly complete code style formatting.

2. The built-in function append changes the scaling algorithm of slices

We all know that when append operates on a slice, once the slice is full (len==cap), append will reallocate a larger underlying array, and then copy the current slice elements to the new underlying array. Usually, when the size is small, append will be expanded by 2 times the cap. When the size is large, for example, it is already 1024, then Go 1.17 will not double allocate. The algorithm in Go 1.18 has been changed to make the changes before and after a threshold smoother. For the specific algorithm, please see the following part of the logic in the growslice function in \$GOROOT/src/runtime/slice.go:

 func growslice(et *_type, old slice, cap int) slice { ... ... newcap := old.cap doublecap := newcap + newcap if cap > doublecap { newcap = cap } else { const threshold = 256 if old.cap < threshold { newcap = doublecap } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < cap { // Transition from growing 2x for small slices // to growing 1.25x for large slices. This formula // gives a smooth-ish transition between the two. newcap += (newcap + 3*threshold) / 4 } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { newcap = cap } } } ... ... }

In addition, from the code point of view, unlike Go 1.17, which uses 1024 as the size boundary, Go 1.18 uses 256 as the threshold. Everyone should pay attention to this.

3. Added net/netip package

The Go 1.18 standard library added the netip package under net. This stems from a problem that former Go core developer Brad Fitzpatrick encountered in his startup project tailscale . Brad found that the existing net.IP in the standard library, which represents IP-related information, has as many deficiencies as follows:

So Brad proposes to add a new representation of IP that occupies less memory, is immutable and comparable, and can be used as a map key . This is netip.Addr and a series of types and methods around netip.Addr.

There is still a lot of content about the netip package. You can check the ref of the netip package to learn more about this package.

4. Two important security changes

Security issues are getting worse, and the Go standard library is keeping pace with security trends.

In Go 1.18, the tls client will use the TLS 1.2 version by default. Of course, if you explicitly set Config.MinVersion to VersionTLS10, TLS 1.0 and 1.1 can still be used.

Additionally, the crypto/x509 package in Go 1.18 will by default reject certificates signed with a SHA-1 hash function (except for self-signed ones). SHA-1 is temporarily supported with GODEBUG=x509sha1=1, but as of Go 1.19, SHA-1 will be permanently kicked out.

5. Added Cut function to strings package and bytes package

Both the strings package and the bytes package have added the utility function Cut (Note: the strings and bytes packages have a long tradition of maintaining API consistency). Taking a string as an example, the semantics of the Cut function is to “cut” a certain string in an input string. The prototype of the Cut function is as follows:

 func Cut(s, sep string) (before, after string, found bool)

If the part to be cut is not found, the final return value is false, before is the original string s, and after is “”.

 var s = "hello, golang" b, a, f := strings.Cut(s, "java") fmt.Printf("before=%s, after=%s, found=%t\n", b, a, f) // before=hello, golang, after=, found=false

If the part to be cut is found, the final return value is true, before is the string in front of the “cut off part”, and after is the string behind the “cut off part”.

 b, a, f = strings.Cut(s, "lang") fmt.Printf("before=%s, after=%s, found=%t\n", b, a, f) // before=hello, go, after=, found=true

If there are multiple strings in the input string that match the part to be cut, the Cut function will only cut the first matching string.

 b, a, f = strings.Cut(s, "o") fmt.Printf("before=%s, after=%s, found=%t\n", b, a, f) // before=hell, after=, golang, found=true

6. runtime/pprof accuracy improvement

Go 1.18 runtime/pprof uses per-thread timers to drive sampling on Linux. The purpose is to improve the accuracy of sampling data under high load and reduce data loss or inaccuracy .

7. Added Mutex.TryLock, RWMutex.TryLock and RWMutex.TryRLock to sync package

At the strong request of the community, the Go team added Mutex.TryLock, RWMutex.TryLock and RWMutex.TryRLock to the sync package. But to be honest, I haven’t personally encountered a situation where I have to use TryLock. The Go team also gives usage hints in the comments of the TryLock method: note that while correct uses of TryLock do exist, they are rare, and uses of TryLock are often a sign of deeper problems with mutex in a particular use .

Try not to use it up!

V. Summary

From the above content, Go 1.18 is really a big change version. Many changes are worth further study and exploration. Since Go 1.18 introduced generics, I would personally recommend holding off on using them in production. Just like after the introduction of the go module, it gradually matured after go 1.11~go 1.16, and the maturity of Go generics must have at least 2-3 versions. At this stage, focus on learning about generics and how to use generics to improve our code, but also pay attention: generics greatly increase the complexity of the code, and the code that uses generics is more readable There is bound to be a decline in the aspect. Don’t abuse generics, and don’t go to the tricky tricks that are obviously used by C++ templates. That goes against the design philosophy of the Go language .


“Gopher Tribe” Knowledge Planet aims to create a high-quality Go learning and advanced community! High-quality first published Go technical articles, “three-day” first published reading rights, analysis of the current situation of Go language development twice a year, reading the fresh Gopher daily 1 hour in advance every day, online courses, technical columns, book content preview, must answer within 6 hours Guaranteed to meet all your needs about the Go language ecosystem! In 2022, the Gopher tribe will be fully revised, and will continue to share knowledge, skills and practices in the Go language and Go application fields, and add many forms of interaction. Everyone is welcome to join!

img{512x368}

img{512x368}

img{512x368}

img{512x368}

img{512x368}

I love texting : Enterprise-level SMS platform customization development expert https://51smspush.com/. smspush : A customized SMS platform that can be deployed within the enterprise, with three-network coverage, not afraid of large concurrent access, and can be customized and expanded; the content of the SMS is determined by you, no longer bound, with rich interfaces, long SMS support, and optional signature. On April 8, 2020, China’s three major telecom operators jointly released the “5G Message White Paper”, and the 51 SMS platform will also be newly upgraded to the “51 Commercial Message Platform” to fully support 5G RCS messages.

The famous cloud hosting service provider DigitalOcean released the latest hosting plan. The entry-level Droplet configuration is upgraded to: 1 core CPU, 1G memory, 25G high-speed SSD, and the price is 5$/month. Friends who need to use DigitalOcean can open this link : https://ift.tt/xKeoXzt to open your DO host road.

Gopher Daily Archive Repository – https://ift.tt/cJPBm3K

my contact information:

  • Weibo: https://ift.tt/Efp56n1
  • WeChat public account: iamtonybai
  • Blog: tonybai.com
  • github: https://ift.tt/HZyCrq9
  • “Gopher Tribe” Planet of Knowledge: https://ift.tt/lckK0Dw

Business cooperation methods: writing, publishing books, training, online courses, partnership entrepreneurship, consulting, advertising cooperation.

© 2022, bigwhite . All rights reserved.

This article is reprinted from https://tonybai.com/2022/04/20/some-changes-in-go-1-18/
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment