Three types of mistakes Golang beginners are prone to make

Source: Internet
Author: User
Tags uppercase letter
This is a creation in Article, where the information may have evolved or changed.

Preface

I have been learning and using Golang has been one months, although the characteristics of Golang, simple syntax and powerful, but as a beginner, will inevitably commit some people have made mistakes. The author on the basis of practice, will be easy for beginners to make mistakes to comb, temporarily summed up three kinds of errors, first share to everyone, hope to have certain help.

Resource Close

The resources here include files, database connections, and socket connections, and we take file operations as an example to illustrate common resource shutdown errors.

A code example of a file operation:

file, err := os.Open("test.go") if err != nil {    fmt.Println("open file failed:", err)    return}...

Some students wrote this began to focus on business code, and finally "forgot" to write off the file operation code. As everyone knows, here buried a curse. In Linux, everything is file, and when there are too many open files, it triggers a system error of "Too many open files", causing the entire system to crash.

We add code to the close file operation as follows:

file, err := os.Open("test.go")defer file.Close()if err != nil {    fmt.Println("open file failed:", err)    return}...

Golang provides a very useful keyword Defer,defer statement means that the code is executed automatically when the function exits, regardless of the program's exception. Unfortunately, the above modification introduces a new problem, that is, if the file is opened incorrectly, call the files. Close causes the program to throw an exception (panic), so the correct modification should be file. Close is placed after the error check, as follows:

file, err := os.Open("test.go")if err != nil {    fmt.Println("open file failed:", err)    return}defer file.Close()...

Case of variable

Golang is very stingy with keyword additions, where there are no keywords such as private, protected, and public. To make a symbol visible to other packages (that is, accessible), you need to define the symbol to start with an uppercase letter that includes interfaces, types, functions, variables, and so on.

For those who care more about aesthetics, especially programmers working on a Linux platform, a function name or variable name that starts with an uppercase letter may make them feel less comfortable, and they adhere strictly to the principle of minimal visibility, and the interface name and class name start with a lowercase letter that will make them very tangled. When they write their own code, it may be handy to change the function name or variable name to start with a lowercase letter, when the interface name or type name that starts with a lowercase letter conflict (in-package visibility), but also have to worry about another name. If you are not careful, the outer visibility of the symbol rename to start with a lowercase letter, you will encounter a compilation error, that is clearly signed but can not find, but this for some programming experience programmer is better to solve.

The following example for Golang beginners, even some programming experience, it is more difficult to troubleshoot, often take a little more time.

type Position struct {    X int     Y int    Z int}type Student struct {    Name string    Sex string    Age int    position Position}func main(){    position1 := Position{10, 20, 30}    student1 := Student{"zhangsan", "male", 20, position1}    position2 := Position{15, 10, 20}    student2 := Student{"lisi", "female", 18, position2}        var srcSlice = make([]Student, 2)    srcSlice[0] = student1    srcSlice[1] = student2    fmt.Printf("Init:srcSlice is : %v\n", srcSlice)    data, err := json.Marshal(srcSlice)    if err != nil{        fmt.Printf("Serialize:json.Marshal error! %v\n", err)        return    }    var dstSliece = make([]Student, 2)    err = json.Unmarshal(data, &dstSliece)    if err != nil {        fmt.Printf("Deserialize: json.Unmarshal error! %v\n", err)        return    }    fmt.Printf("Deserialize:dstSlice is : %v\n", dstSliece)}

Let's look at the print results:

Init:srcSlice is : [{zhangsan male 20 {10 20 30}} {lisi female 18 {15 10 20}}]Deserialize:dstSliece is : [{zhangsan male 20 {0 0 0}} {lisi female 18 {0 0 0}}]

Surprisingly, the object data that we get after deserialization is wrong, and JSON. Unmarshal does not return any exceptions.
For further positioning, we print the serialized JSON string:

Serialize:data is : [{"Name":"zhangsan","Sex":"male","Age":20},{"Name":"lisi","Sex":"female","Age":18}]

As can be seen from the printed results, position data is lost, which makes us think of the visibility, that is, the uppercase symbol is visible outside the package. By walking through the code, we find that in the definition of student, the variable name of position begins with lowercase:

type Student struct {    Name string    Sex string    Age int    position Position}

For those of you who are accustomed to writing C/c++/java code, changing the name of this variable becomes very tangled, and the experience of "beginning the class name capitalized, the object name starts with lowercase" is no longer applicable and has to have a less shunliu name, such as an abbreviation:

type Student struct {    Name string    Sex string    Age int    Posi Position}

Run the program again, the results are normal, print as follows:

Init:srcSlice is : [{zhangsan male 20 {10 20 30}} {lisi female 18 {15 10 20}}]Serialize:data is : [{"Name":"zhangsan","Sex":"male","Age":20,"Posi":{"X":10,"Y":20,"Z":30}},{"Name":"lisi","Sex":"female","Age":18,"Posi":{"X":15,"Y":10,"Z":20}}]Deserialize:dstSliece is : [{zhangsan male 20 {10 20 30}} {lisi female 18 {15 10 20}}]

For JSON strings, a lot of people like all lowercase, for the capital start key feel very dazzling, we continue to improve:

type Position struct {    X int `json:"x"`    Y int `json:"y"`    Z int `json:"z"`}type Student struct {    Name string `json:"name"`    Sex string `json:"sex"`    Age int `json:"age"`    Posi Position `json:"position"`}

The code between two diagonal points, for example json:"name" , is that the name field, when encoded from a struct instance to a JSON data format, uses name as the name, which can be considered a way to rename.

Run the program again, and the result is what we expect, printed as follows:

Init:srcSlice is : [{zhangsan male 20 {10 20 30}} {lisi female 18 {15 10 20}}]Serialize:data is : [{"name":"zhangsan","sex":"male","age":20,"position":{"x":10,"y":20,"z":30}},{"name":"lisi","sex":"female","age":18,"position":{"x":15,"y":10,"z":20}}]Deserialize:dstSliece is : [{zhangsan male 20 {10 20 30}} {lisi female 18 {15 10 20}}]

Initialization of local variables (: =)

There is a local variable initialization method in Golang that uses the combination of a colon and an equal sign ": =" to declare and initialize variables, which makes it convenient for us to use local variables.

The code that initializes a local variable can be written like this:

v := 10

The specified type is no longer required, and the go compiler can deduce from the right value of the initialization expression which type the variable should be declared, which makes the go language look a bit like a dynamic type language, although the go language is actually a strongly typed language (static type language).

Description: The feeling is somewhat similar to the function of the Auto keyword in c++11

Golang introduced a standard mode of error handling, that is, the wrong interface, everyone is too much love, so that obviously only the bool property of the return value or variable is modified with error, we look at an example:

port, err := createPort()if err != nil {    return}veth, err := createVeth()if err != nil {    return}err = insert()if err != nil {    return}...

Here's the two local variable err is the same variable? The answer is yes.

There is a limit to the initialization of variables by the combination of a colon and an equal sign ": =", where at least one of the variables appearing on the left side of ": =" is not declared, or the compilation fails.

Many people do not know this rule, then write the following code:

port, errPort := createPort()if errPort != nil {    return}veth, errVeth := createVeth()if errVeth != nil {    return}errInsert := insert()if errInsert != nil {    return}...

For those who like to write simple beautiful code can not accept such a name, such as Errport, Errveth and Errinsert, so for the error interface variable name, in the author's heart of baby names only one, that is err.

In addition to naming, another common mistake is that local variables may obscure or hide global variables because local variables initialized by the ": =" method do not see global variables.

Let's look at a piece of code first:

var n intfunc foo() (int, error) {    return 5, nil}func bar() {    fmt.Println("bar n:", n) }func main() {    n, err := foo()    if err != nil {        fmt.Println(err)        return    }    bar()    fmt.Println("main n:", n)}

The intent of this code is to define a global variable n within a package, assign n with the return value of the Foo function, and use n in the bar function.
The expected result is that both bar () and main () output 5, but the results after the program run are not what we expected:

bar n: 0main n: 5

By adding further printing, it is found that the address of N of the main function called the Foo function (0x201d2210) is not the same as the address of the global variable N (0X56B4A4), that is, the former is a local variable, and from the bar function in the print view, The global variable n is not assigned a return value of 5 when the Foo function returns, and is still the initial default value of 0.

The initial understanding of the statement "N, Err: = foo ()" Is that Golang defines the new variable err,n as the initial defined global variable. But the reality is that for a variable defined with ": =", if the new variable n is not in a scope with the variable defined by the same name (this is the global variable N), then Golang defines the variable n and obscures or hides the variable with the same name in the large scope, which is the real culprit that caused the problem.

Know the real killer after the very good solution, that is, we use "=" instead of ": =":

func main() {    var err error    n, err = foo()    if err != nil {        fmt.Println(err)        return    }    bar()    fmt.Println("main n:", n)}

Run the program again and the results are exactly what you expect:

bar n: 5main n: 5

Summary

This article summarizes three kinds of errors that Golang beginners can make, including resource closing, symbol capitalization and local variable initialization, hoping to help a novice like me, so as to take a little detour in the process of business implementation, faster and more secure business-oriented programming, continuous delivery of value to the user.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.