golang1.13 important new features in the new

Citation

golang1.13 released for a month, it will list a few of the more important features. We will change the language, stock changes and improvements tool chain of these three areas one by one the new features introduced in the new version.

Language change

go team has been committed to forward-compatible version 1.x, so although 1.13 As a first began to transition go2 version, language change introduced is minimal, primarily only these two things: more literal and digital improved panic information.

Digital literal

Digital literal is all too familiar things, such as 100, 0.99, 1.and so on.

Curiously, however, before 1.13 golang support only literal decimal and hexadecimal numbers, but in other languages ​​widely supported binary and octal was not supported. For example, the following code can not be compiled:

fmt.Println(0b101)
fmt.Println(0o10)

In go1.13 above literal syntax already supported you can 0bor 0Bto indicate a literal binary digits, and prefix 0oand 0Oto indicate octal literal. It is noteworthy that although the two way can be, but gofmt default all lowercase, so I recommend using 0band 0omake your code as much as possible unified style.

Another change is the introduction of digital literal hexadecimal floating point support.

Floating point numbers are hexadecimal represented in hex with float method, it should be noted that this refers not to the floating point numbers in hexadecimal form corresponding to the binary value, but rather in the form of hexadecimal numbers as follows:

0X十六进制整数部分.十六进制小数部分p指数

And wherein the integer and fractional part as ordinary floating-point literals can be omitted, the default is omitted, 0 part. P + portion index can not be omitted, there may be a symbol index, which is the index value of 2.

The final result of a floating point hexadecimal literals, assuming part of the previous p-value a, p is the index B, the final values are as follows: a * 2^b.

Looks like scientific notation, which is in fact replaced by the e p, calculated from the index 10 becomes 2. Moreover, because the intake is 16 per 1, it 0x0.1p0looks like 0.1, but it represents 1/16, and 0x0.01p0it is 1/16 1/16, has shown signs would be less intuitive, but after the habit is not a problem a. For example point:

Binary and octal literal is more commonly used, that hex float it? The answer is more accurate and uniform expression.

0x0.1p0Represents the decimal value of 0.0625, and 0x0.01p0is 0.00390625, it has exceeded float32 accuracy range, so the floating point hexadecimal literal value can be represented more accurately in a limited range of accuracy. Unified expression naturally not have to explain, hexadecimal expression habit developers more willing to use a similar form.

Specific examples may reference herein .

Finally, for digital literal as well as a small improvement, it is now possible to increase the readability of numbers separated by underscores. for example:

fmt.Println(100000000)
fmt.Println(1_0000_0000)
fmt.Println(0xff_ff_ff)

Delimiter may appear anywhere, but like 0xintermediate regarded as a complete symbol or the like can not be inserted into the underline, the number of characters is not defined between the separator must be equal, but for readability is preferred that each diet according to the prior three or four digit numbers separated by one.

Index out of bounds error perfection

While I be classified as language changes, but in fact it is defined as a run-time improvement is more appropriate.

As we all know golang of bounds array references is 0 and slice tolerated, once the cross-border will panic, such as the following examples:

package main

import "fmt"

func main() {
        arr := [...]int{1,2,3,4,5}
        for i := 0; i <= len(arr); i++ {
                fmt.Println(arr[i])
        }
}

If you run this program you will receive not less than a complaint:

The example here is very simple, it is not very difficult call stack information Looking back, you can easily locate the problem was, but if the call chain or darker you are in a highly concurrent program, things get in trouble, or rely logs and debugging the final analysis excluded a lot of noise to locate the problem, either rely on single-step breakpoint debugging, no matter what kind of need to spend a lot of energy, but we think the core issue until just why cross-border, and then a light step, we might just know sometimes lead the value of cross-border can roughly determine the cause of the problem, unfortunately panic information provided does not include content until golang1.13.

Now golang will lead to print out the value of cross-border, it is undoubtedly the snow, sending carbon:

Of course, panic and then the information is not perfect panacea, improve unit testing and rigorous work bug is the best shot.

Tool chain improvement

Change language level is not great, but not the same tool chain, in addition to the program in addition to godoc, the biggest change is still concentrated on the go modules.

The golang joined the three environment variables to control the behavior of common modules, and are described separately below.

GOPROXY

In fact, this variable is 1.12 on the introduction, this time adding to its default value https://proxy.golang.org,direct, which is a comma-separated list of values of two variables and behind it is the same, which means no direct connection through a proxy directly, if set to off, then download any binary package.

When go get command to get the package, etc., will in turn look from left to right, if no matching package is found, it will error.

Benefits proxy of natural Needless to say, it allows developers to unimpeded access to domestic package some domestic environment can not be obtained. More important is the default proxy is the official and maintenance, compared to a third-party program for security with greater protection.

GOSUMDB

This variable is actually equivalent to a specified by the official management of online go.sum database. Before we take a look at specific description is to verify how golang of packages:

  1. go get downloaded package will create a separate hash string stored in go.sum file and all documents based on go.mod download files;
  2. Download the package will be cache, compared with the recalculated value of go.sum, appears each time you compile or manually go mod verify inconsistent security error will be reported.

This mechanism is established in the local cache will not throughout the development life cycle on changes (because dependent libraries are rarely updated version, unless major security problems), the above-mentioned mechanism to avoid others from updating or rely on locally malicious tampering, but more security problems now occur in remote environments, so this mechanism there is a big security risk.

Fortunately, he joined the GOSUMDB, it defaults to "sum.golang.org", inaccessible parts of the country, can be changed to "sum.golang.google.cn". Now working mechanism is as follows:

  1. go get the download package and a checksum calculation, calculate the first checks whether the file is already present in go.sum, if not then go GOSUMDB check, the check is written and consistent go.sum file; otherwise error
  2. If the verifying packet and the corresponding version is already in go.sum, the request is not GOSUMDB, the remaining steps and as old mechanisms.

Security has been enhanced.

GOPRIVATE

Last, but it is GOPRIVATE, empty by default, in which you can use something like Linux glob wildcard syntax to specify certain or a certain type of package is not downloaded from a proxy, such as some rpc package automatically generated package, these proxy in does not exist, and even upload up does not make sense, so you need to write it in GOPRIVATE.

There is also a similar thereto environment variable called GONOPROXY, as the value of the form, function basically the same, but it will cover GOPRIVATE. For example, it is set to none when all packets will be available from the proxy.

From the point of view of these changes go a unified team is always looking for a solution that can package management fine-grained control, and although npm, pypi there is a huge gap, it is still a solid step on the road to success.

New features standard library

Each new release will bring new features to the standard library a lot of new features, this is no exception.

This section will introduce a new small features, as well as an important new changes.

Determining whether the variable is the value of 0

golang any type of zero values ​​are clearly defined, but unfortunately different different types of zero value, especially those self-defined types, if you want to determine the value of a variable is 0 then the expansion will be difficult to write complicated and cumbersome code.

Therefore reflect new in this function simplifies the operation:

package main

import (
        "fmt"
        "reflect"
)

func main() {
        a := 0
        b := 1
        c := ""
        d := "a"
        fmt.Println(reflect.ValueOf(a).IsZero()) // true
        fmt.Println(reflect.ValueOf(b).IsZero()) // false
        fmt.Println(reflect.ValueOf(c).IsZero()) // true
        fmt.Println(reflect.ValueOf(d).IsZero()) // false
}

Of course, once the reflection performance at the expense of higher consumption, so the specific choice Referring also to the actual environment.

Innovation error handling

In fact, hardly innovative, but the existing practice of minor repairs. golang team always feel that error since it is the value it must have reflected the quirks of equal value operations, so overall still very strange.

First to introduce the concept of chain of errors (error chains) of.

In 1.13, we can achieve a Unwrap method for error in order to achieve packaging error, such as:

type PermError {
        os.SyscallError
        Pid uint
        Uid uint
}

func (err *PermError) String() string {
        return fmt.Sprintf("permission error:\npid:%v\nuid:\ninfo:%v", err.Pid, err.Uid, err.SyscallError)
}

func (err *PermError) Error() string {
        return err.String()
}

// 重点在这里
func (err *PermError) Unwrap() error {
        return err.SyscallError
}

Suppose we packed a permission-based SyscallError errors, including all error triggered because of permission issues. StringAnd Errormethods are wrong methods will be implemented in conventional custom, we look at the focus Unwrapmethod.

UnwrapLiterally, to packaging, that is, we put on a layer of packaged wrong again separated and returned. os.SyscallErrorAlso achieved Unwrap, so you can continue to drill up direct access to the most primitive do not realize that until the error Unwrap of. We said from the beginning to the topmost PermError error is an error chain.

If we return Unwrap → pointing object, will form the following structure:

PermError → os.SyscallError → error

It may also be present a more complex structure:
A → Err1 ___________
|
V
B Err3 → → → error Err2

This would no doubt enhance the expressive wrong, if you do not own a single definition of the type of error, just want some additional information, you can rely on fmt.Errorf:

newErr := fmt.Errorf("permission error:\npid:%v\nuid:\ninfo:%w", pid, uid, sysErr)
sysErr == newErr.(interface {Unwrap() error}).Unwrap()

fmt.ErrorfThe new placeholder %wcan appear only once in a format string, he would fill the error message in, and then return to a realization of the new error Unwrap it returns passed the error. Another proposal in the Interface Wrapper has not yet achieved, but I do use the standard library implements Wrapper functions in the above approach.

Because there is an error chain, we can not simply use the equal sign determination based on the value of the error, but the advantage is that we can now determine based on the type of error.

In order to continue to allow error to show his value semantics, errors increased Is the bag and their Unwrap As well as auxiliary functions.

Unwrap

errors.UnwrapIt calls arguments passed Unwrap method, As Is, and use it to trace the entire chain of errors.

Like the previous section of this code can be simplified to:

newErr := fmt.Errorf("permission error:\npid:%v\nuid:\ninfo:%w", pid, uid, sysErr)
sysErr == errors.Unwrap(newErr).Unwrap()

Is

We mentioned relatively equal number of often no longer held, with sometimes only a package for another error, this error is generated when another has occurred, and this time we need only compare the error value is in the upper it can, this time you need to errors.Ishelp the:

newErr := fmt.Errorf("permission error:\npid:%v\nuid:\ninfo:%w", pid, uid, sysErr)
errors.Is(newErr, sysErr)
errors.Is(newErr, os.ErrExists)

You never know how the program will be extended, we do not know what the future will change the relationship between the error, therefore always use Is instead of == is infallible.

But always be exceptions, for example, io.EOFyou do not need to use the Is to compare, because its meaning is not really a program error, and generally no one would wrap it.

As

In addition to traditional value-based judgment, for a certain type of error is a common processing requirements. The foregoing example A, B are from error, we assumed to handle all based on the error, the error is the common approach is to rely on the switch or comparing the ability polymorphic base class.

The obvious approach is to switch judgment will lead to a large number of duplicate code, but extends difficult; but there is no inheritance only in combination golang years, so there are run-time polymorphism only interface capabilities, this time we can only help to make the wrong chain errors.Asto help the:

// 注意As的第二个参数只能是你需要判断的类型的指针,不可以直接传一个nil进去
var p1 *os.SyscallError
var p2 *os.PathError
errors.As(newErr, &p1)
errors.As(newErr, &p2)

If the type p1 and p2 on the wrong chain newErr is located, it returns true, implements a very simple polymorphic effect. As always used to replace if _, ok := err.(type); oksuch code.

Of course, the above function on the one hand make you less to write a lot of code, on the other hand relies heavily on reflection, especially in a long chain of errors repeatedly traced back many times as needed, so there are two advice:

  1. Do transition package, nothing is to add a layer of indirection can not be resolved, but too many intermediate layer not only affects the performance will interfere with ongoing maintenance;
  2. If you really care about performance, but also to ensure the expansion of the existing error does not exist (for example io.EOF), then use the traditional program would not hurt.

Personally I do not think the new error-handling method solves the problem of what nature, but as a first step to try, or worthy of recognition.

Guess you like

Origin www.cnblogs.com/apocelipes/p/11600855.html