A few days ago, I saw some good little knowledge points about Go on the Internet, and I will summarize and share them with you.

The difference between new and make

Both new and make are used in Go to create objects. The new keyword is used in many programming languages, such as C++ and Java, to create objects with new.

In Go, new is also used to create objects. For example, new(T) will create an object for T, assign a zero value to that object, and then return a pointer to T *T. Here we demonstrate three different ways to create a bytes.buffer object and return its pointer.

// Declare a variable, then take its address and assign it to the pointer p
var buf bytes.Buffer
p := &buf

// Use a compound declaration to do it in one step
p := &bytes.Buffer{}

// Using new is also done in one step
p := new(bytes.Buffer)
Copy the code

All three methods of creating objects are equivalent.

Make is also commonly used in everyday programming, but its use is limited to slice, map, and channel. Using make also creates objects, such as make(T), but it returns the value T of the object. Let’s review how make is used.

// Create a slice with length 0 and capacity 8
sl := make([]string.0.8)

// Create a blocked channel
ch := make(chan int)

// Create a map
m := make(map[string]string)
Copy the code

The objects created using make above return the corresponding value types.

To summarize the differences between new and make:

1. New returns a pointer to T and make returns the value of T.

2. Make can only be used to create slice, map, and channel.

Variable names do not have types

Dave Cheney, the Go guru, has an interesting metaphor for variable naming: you name variables like you name your pet. Don’t put “XX dog” or “XX cat” in the name, because everyone knows it’s a dog or a cat.

So your variable name should describe the content of the variable, not the type of the variable.

var usersMap map[string]*User
Copy the code

UsersMap is a nice variable name that describes the map mapping type of *User. However, because Go is a static language, we do not need to assign a variable name to a map as we do in a dynamic language, because we are afraid of assigning the wrong type to it, so the suffix map is redundant.

Let’s name a few more variables this way.

var (
   companiesMap map[string]*Company
   productsMap  map[string]*Products
)
Copy the code

Now, we have named three variables of map type: usersMap, companiesMap, and productsMap, where their corresponding values are different struct types. When we assign *User to productsMap, the compiler will report an error, unlike in dynamic languages, which can only report an error at runtime.

In this case, adding the Map suffix does not better describe the variable, but is simply a superfluous suffix. It is therefore not recommended to include a type in a variable name.

The same is true for method naming.

type Config struct {
    //
}

func (c *Config) WriteConfig(w io.Writer) {
    //
}

// would be better
func (c *Config) Write(w io.Writer) {
    //
}
Copy the code

In the code above, the Config suffix is also redundant because WriteConfig is the *Config method.

In addition, the package name should not use the name of the type, like the context type in the context package. When we import the context package, we should only use the variable name like CTX, not the context.

// This is a strange name, Func WriteLog(context context. context, message string) // Can only be named func WriteLog(CTX context. context, message string)Copy the code

conclusion

The purpose of variable naming in Go is to be concise, and the variable name should be independent of its type.

Catch Panic with the named return value

Imagine writing code that uses a function that can panic, that can panic, and you can’t change that function, like this:

func pressButton(a) {
    fmt.Println("I'm Mr. Meeseeks, look at me!!")
    // other stuff then happens, but if Jerry asks to
    // remove 2 strokes from his golf game...
    panic("It's gettin' weird!")}Copy the code

Even though this function can panic, you still have to use it, and when it does panic we can catch the error, like this:

func doStuff(a) error {
    var err error
    // If there is a panic we need to recover in a deferred func
    defer func(a) {
        if r := recover(a); r ! =nil {
            err = errors.New("the meeseeks went crazy!")
        }
    }()

    pressButton()
    return err
}
Copy the code

When panic occurs in a pressButton, we expect to return an error, but return nil. Because the pressButton panic occurs, it returns directly, and does not return err.

Fixing this problem is as simple as giving error a variable name.

func doStuff(a) (err error) {
    // If there is a panic we need to recover in a deferred func
    defer func(a) {
        if r := recover(a); r ! =nil {
	    err = errors.New("the meeseeks went crazy!")
	}
    }()

    pressButton()
    return err
}
Copy the code

reference

1. Understanding the Go make the difference between the new and “sanyuesha.com/2017/07/26/…

2. Using named return variables to Capture Panics in Go www.calhoun.io/using-named…

3. dave.cheney.net/2019/01/29/…

Thank you for reading. Welcome to comment and share

Source: wechat official account “Go Back-end Dry Goods”

All kinds of Go, back-end technology, interview questions to share, welcome to pay attention to