Go language Process Control structure and function analysis

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

Like other programming languages, the go language has its own process control structure, such as conditional branching, looping statements, and so on. In addition, functions in the Go language require some keyword retouching to implement different functions. This article discusses the process control structure and functions of the go language together.

Process Control

Process Control is the greatest invention in programming languages, because with it, you can express complex logic through a very simple process description. There are three main categories of process Control in go: Conditional judgment, cyclic control and unconditional jump.

If

If it is perhaps the most common in a variety of programming languages, its syntax is summed up: do something if you meet the criteria, or do another thing.

Go inside the IF condition judgment statement does not need parentheses, as shown in the following code:

If x > {    fmt. Println ("X is greater than")} else {    fmt. Println ("X is less than 10")}

The If of Go is also a strong place is the conditional judgment statement inside allows to declare a variable, the scope of the variable can only be within the logical block of the condition, other places will not work, as follows:

Calculates the Get value x, and then determines whether it is greater than 10, based on the size returned by X. If x: = Computedvalue (); X > {    fmt. Println ("X is greater than")} else {    fmt. Println ("X is less than 10")}//this place if this call compiles an error, because X is the variable FMT inside the condition. PRINTLN (x)

Multiple conditions are as follows:

if integer = = 3 {    FMT. Println ("The integer is equal to 3")} else if integer < 3 {    FMT. Println ("The integer is less than 3")} else {    fmt. Println ("The integer is greater than 3")}

Goto

Go has a goto statement-please use it wisely. Use Goto to jump to a label that must be defined within the current function. For example, suppose such a loop:

Func MyFunc () {    I: = 0Here:   //The first word of this line, ending with a colon as a label    println (i)    i++    goto   here//jump to here to}

The label signature is case-sensitive.

For

One of the most powerful control logic in Go is for, which can be used to iterate through the data and act as a while to control logic and to iterate. Its syntax is as follows:

For expression1; expression2; Expression3 {    //...}

Expression1, Expression2, and expression3 are expressions, where expression1 and expression3 are variable declarations or function call return values, Expression2 is used for conditional judgment, The expression1 is called before the loop starts, and Expression3 is called at the end of each round of the cycle.

An example is more useful than that, so let's take a look at the following example:

Package Mainimport "FMT" Func Main () {    sum: = 0;    For index:=0; Index < 10; index++ {        sum + = Index    }    FMT. Println ("Sum is equal to", sum)}//output: Sum is equal to 45

There are times when multiple assignment operations are required, because there is no operator in go, you can use parallel assignment I, j = i+1, j-1

Sometimes if we ignore expression1 and Expression3:

Sum: = 1for; Sum <;  {    sum + = sum}

which can also be omitted, then become the code below, is not familiar? Yes, this is the function of the while.

Sum: = 1for Sum < $ {    sum + = sum}

In the loop there are two key operations break and continue, the break operation is jumping out of the current loop, continue is skipping this cycle. When nested too deep, break can be used in conjunction with the label, that is, to jump to the location specified in the label, detailed reference to the following example:

For index: = 10; index>0; index--{    If index = = 5{break        //or Continue    }    FMT. PRINTLN (index)}//break print out 10, 9, 8, 7, 6//continue print out 10, 9, 8, 7, 6, 4, 3, 2, 1

Break and continue can also follow the label to jump to the outer loop in multiple loops

The for Mate range can be used to read slice and map data:

For K,v:=range map {    FMT. PRINTLN ("Map ' s key:", K)    FMT. PRINTLN ("Map ' s val:", v)}

Switch

Sometimes you need to write a lot of if-else to implement some logic processing, this time the code looks very ugly and lengthy, but also not easy to later maintenance, this time switch will be able to solve the problem well. Its syntax is as follows

Switch sexpr {case EXPR1:    some instructionscase expr2:    Some other instructionscase EXPR3:    Some other Instructionsdefault: Other    code}

The types of sexpr and Expr1, EXPR2, and EXPR3 must be identical. The switch of Go is very flexible, the expression does not have to be a constant or an integer, the process is performed from top to bottom until a match is found, and if switch has no expression, it matches true.

I: = 10switch I {Case 1:    FMT. Println ("I was equal to 1") Case 2, 3, 4:    FMT. Println ("I am equal to 2, 3 or 4") Case:    FMT. Println ("I am equal to") Default:    FMT. Println ("All I know are that I am an integer")}

In line 5th, we aggregate a number of values into a case, while the go inside switch defaults to the same as each case last with a break, after the successful match does not automatically down the other case, but out of the entire switch, However, you can use Fallthrough to enforce the following case code.

Integer: = 6switch integer {case    4:    FMT. Println ("The Integer is <= 4")    Fallthrough case    5:    FMT. Println ("The Integer is <= 5")    Fallthrough case    6:    FMT. Println ("The Integer is <= 6")    Fallthrough case    7:    FMT. Println ("The Integer is <= 7")    Fallthrough case    8:    FMT. Println ("The integer was <= 8")    fallthrough    default:    FMT. PRINTLN ("Default Case")}

The above program will output

The integer was <= 6The integer was <= 7The integer is <= 8default case

Function

function is the core design of go inside, it is declared by the keyword func, its format is as follows:

Func funcName (input1 type1, Input2 type2) (output1 type1, Output2 type2) {//    here is the process logic code    //Return multiple values return    Value1, value2}

The above code we see

1. The keyword func is used to declare a function funcname
2. A function can have one or more parameters, followed by a type, passed, delimited
3. Function can return multiple values
4. The above return value declares two variables output1 and output2, if you do not want to declare also can, directly on two types
5. If you have only one return value and do not declare a return value variable, you can omit the parentheses that include the return value
6. If there is no return value, then the last return message is omitted directly
7. If there is a return value, you must add a return statement to the outer layer of the function

Let's take a look at an example of the actual application of the function (to calculate the max value)

Package Mainimport "FMT"//returns the maximum value in a, B. Func Max (A, b int) int {    If a > B {        return a    }    return B}func main ( {    x: = 3    y: = 4    Z: = 5    Max_xy: = max (x, y)//Call function Max (x, y)    max_xz: = max (x, z)//Call function Max (x, z)    F Mt. Printf ("Max (%d,%d) =%d\n", x, Y, Max_xy)    FMT. Printf ("Max (%d,%d) =%d\n", X, Z, MAX_XZ)    FMT. Printf ("Max (%d,%d) =%d\n", Y, Z, Max (y,z))//can also be called directly in this}

In this case, we can see that the Max function has two parameters, all of which are of type int, then the type of the first variable can be omitted (that is, a, b int, rather than a int, the second int), the default is the type closest to it, the same as more than 2 variables of the same type, or a return value. At the same time we notice that its return value is a type, this is the ellipsis.

Multiple return values

The Go language features more advanced than C, one of which is that functions can return multiple values.

Let's look at the example directly on the code:

Package Mainimport "FMT"//Return A+b and A*bfunc sumandproduct (A, B int) (int, int) {    return a+b, A*b}func main () {    x: = 3    y: = 4    xplusy, Xtimesy: = Sumandproduct (x, y)    fmt. Printf ("%d +%d =%d\n", x, Y, xplusy)    FMT. Printf ("%d *%d =%d\n", x, Y, Xtimesy)}

In the example above we can see that two parameters are returned directly, and of course we can also name the variables that return the parameters, this example only uses two types, we can change the definition as follows, and then return without having to take the variable name, because it is initialized directly inside the function. But if your function is exported (capitalized), the official recommendation is to name the return value, because the return value is not named, although it makes the code more concise, but results in poor readability of the resulting document.

Func sumandproduct (A, B int) (add int, multiplied int) {    add = a+b    multiplied = a*b    return}

Variable parameter

The GO function supports variable parameters. The function that accepts the argument is a variable number of arguments. To do this, you first need to define the function to accept the arguments:

Func myfunc (arg ... int) {}

Arg ... int tells go that the function accepts an indefinite number of arguments. Note that the types of these parameters are all int. In the function body, the variable arg is the slice of an int:

For _, N: = range arg {    FMT. Printf ("and the number is:%d\n", N)}

Transmit value and pass pointer

When we pass a parameter value into the called function, it is actually a copy of the value, and when the value of the parameter is modified in the called function, the corresponding argument in the calling function does not change any more because the numeric change only works on copy.

To verify what we said above, let's look at an example

Package Mainimport "FMT"//simple function that implements the operation of parameter +1 func add1 (a int) int {    A = a+1//We changed the value of a to return a    //return a new value}func main () {    x: = 3    fmt. Println ("x =", x)  //should output "x = 3"    x1: = ADD1 (x)  //Call ADD1 (x)    FMT. Println ("x+1 =", x1)//should output "x+1 = 4"    fmt. Println ("x =", x)    //should output "x = 3"}

Did you see it? Although we call the ADD1 function and perform a = a+1 operation in Add1, the value of the x variable in the example above has not changed

The reason is simple: because when we call ADD1, the ADD1 receives the arguments that are actually X's copy, not the x itself.

Then you may ask, if you really need to pass this x itself, what should be done?

This involves the so-called pointers. We know that variables are stored at a certain address in memory, and modifying a variable is actually the memory at the address of the modified variable. Only the ADD1 function knows the address where the x variable is located to modify the value of the X variable. So we need to pass the address of X &x to the function and change the type of the function's argument from int to *int, that is, to the pointer type, in order to modify the value of the x variable in the function. At this point the parameter is still passed by copy, except that the copy is a pointer. Take a look at the following example:

Package Mainimport "FMT"//simple function that implements the operation of parameter +1 func add1 (a *int) int {///note,    *a = *a+1//modified a value    return *a//return new value} Func Main () {    x: = 3    fmt. Println ("x =", x)  ///should output "x = 3"    x1: = Add1 (&x)  //Call ADD1 (&X) to the address of the X.    FMT. Println ("x+1 =", x1)//should output "x+1 = 4"    fmt. Println ("x =", x)    //should output "x = 4"}

In this way, we have achieved the purpose of modifying X. So what are the benefits of passing pointers?

1. Passing pointers allows multiple functions to manipulate the same object.
2. The pointer is relatively lightweight (8bytes), just to pass the memory address, we can use the pointer to pass large volume structure. If passed with a parameter value, a relatively large amount of overhead (memory and time) is spent on each copy. So when you're passing large structures, it's a wise choice to use pointers.
3.Go language String,slice,map These three types of implementations are similar to pointers, so they can be passed directly without having to take an address and pass pointers. (Note: If the function needs to change the length of the slice, the address pass pointer still needs to be taken)

Defer

There is a good design in the go language, the deferred (defer) statement, where you can add multiple defer statements to a function. When the function executes to the last, these defer statements are executed in reverse order, and finally the function returns. Especially when you are doing some open resources operation, encountered errors need to return early, before returning you need to close the corresponding resources, otherwise it is easy to cause problems such as resource leakage. As shown in the following code, we generally write open a resource that works like this:

Func ReadWrite () bool {    file. Open ("file")//Do some work    if Failurex {        file. Close ()        return False    }    if Failurey {        file. Close ()        return False    }    file. Close ()    return True}

We see a lot of duplicated code on it, and the go defer effectively solves this problem. With it, not only is the amount of code reduced a lot, but the program becomes more elegant. The function specified after defer is called before the function exits.

Func ReadWrite () bool {    file. Open ("file")    defer file. Close ()    if Failurex {        return false    }    if Failurey {        return false    }    return True}

If there are many calls to defer, then defer is in LIFO mode, so the following code will output 4 3 2 1 0

For I: = 0; I < 5; i++ {    defer FMT. Printf ("%d", I)}

function as value, type

In go, a function is also a variable, and we can define it by type, which is a type that has all the same parameters and the same return value.

Type typeName func (input1 inputType1, Input2 inputType2 [, ...]) (Result1 resultType1 [, ...])

What is the benefit of a function as a type? That is, you can pass this type of function as a value, see the example below

Package Mainimport "FMT" type testint func (int) bool//declares a function type func isodd (integer int) bool {    if integer%2 = = 0 {
  
   return false    }    return true}func isEven (integer int) bool {    if integer%2 = = 0 {        return true    }    ret  Urn false}//declares a function type in this place as a parameter func filter (slice []int, F testint) []int {    var result []int    for _, Value: = Range Slice {        if f (value) {            result = Append (result, value)        }    }    return Result}func main () {    Slice: = []int {1, 2, 3, 4, 5, 7}    FMT. Println ("slice =", slice)    odd: = Filter (slice, isodd)    //function as a value to pass the    FMT. Println ("Odd Elements of Slice is:", ODD)    even: = Filter (slice, IsEven)  //function as a value to pass the    FMT. Println ("Even elements of Slice is:", even)}
  

functions as values and types are very useful when we write some common interfaces, and by the above example we see that the Testint type is a function type, and then the parameters and return values of the two filter functions are the same as the Testint type, but we can implement many kinds of logic, This makes our program very flexible.

Panic and recover

Go has no exception mechanism like Java, it cannot throw exceptions, but uses the panic and recover mechanisms. It is important to remember that you should use it as a last resort, that is to say, there should be no or little panic in your code. This is a powerful tool, please use it wisely. So, how should we use it?

Panic

is a built-in function that interrupts the original control flow and enters a frightening process. When function f calls panic, the execution of the function f is interrupted, but the delay function in F executes normally, and then F returns to the place where it was called. Where the call is made, the behavior of F is like calling panic. This process continues upward until all called functions in the goroutine that occur panic are returned, at which point the program exits. Panic can be directly called panic generation. It can also be generated by a run-time error, such as an array that accesses out of bounds.

Recover

is a built-in function that allows Goroutine to recover from a panic-entering process. The recover is only valid in the delay function. During normal execution, the call to recover returns nil and has no other effect. If the current goroutine is in panic, call recover can capture the input value of panic and return to normal execution.

The following function demonstrates how to use panic in a procedure

var user = os. Getenv ("user") Func init () {    if USER = = "" {        Panic ("No value for $USER")    }}

The following function checks whether a function as its argument produces panic when executed:

Func throwspanic (f func ()) (b bool) {    defer func () {        if x: = Recover (); X! = Nil {            b = True        }    } ()    F ()//Execute function F, if panic is present in F, you can return return    }

Main function and init function

There are two reserved functions in go: the init function (which can be applied to all package) and the main function (can only be applied to package main). These two functions cannot have any parameters and return values when they are defined. Although it is possible to write any number of INIT functions in a package, it is strongly recommended that users write only one init function per file in a single document, whether for readability or later maintainability.

The GO program automatically calls Init () and main (), so you don't need to call these two functions anywhere. The INIT function in each package is optional, but the package main must contain a main function.

The initialization and execution of the program starts with the main package. If the main package also imports other packages, they are imported sequentially at compile time. Sometimes a package can be imported at the same time by multiple packages, so it will only be imported once (for example, many packages may use the FMT package, but it will only be imported once, because there is no need to import multiple times). When a package is imported, if the package also imports other packages, the other packages are imported, and then the package-level constants and variables in those packages are initialized, followed by the Init function (if any), and so on. When all the imported packages are loaded, the package-level constants and variables in the main package are initialized, and the INIT function in the main package (if present) is executed, and the main function is finally executed. Explains the entire execution process in detail:

Figure 2.6 Main function introduces package initialization flowchart

Import

When we write the go code, we often use the Import command for importing package files, which we often see in the following way:

Import (    "FMT")

Then we can call the code in the following way

Fmt. Println ("Hello World")

Above this fmt is the Go Language standard library, in fact, go to goroot environment variable specified directory to load the module, of course, the import of Go also supports the following two ways to load their own modules:

1. Relative path

Import "./model"//The Model directory of the same directory as the current file, but it is not recommended to import this way

2. Absolute path

Import "Shorturl/model"//Load Gopath/src/shorturl/model module

The above shows some of the import commonly used in several ways, but there are some special import, so many novice very difficult to understand, let's one by one to explain what is the matter

Point operation

We sometimes see the following ways to import packages

Import (    . "FMT")

The point operation means that after the package is imported, you can omit the prefix's package name when you call the package's function, which is the FMT you called earlier. Println ("Hello World") can be omitted as written Println ("Hello World")

Alias operation

Alias operation as the name implies, we can name the package another one that we remember easily.

Import (    F "FMT")

Alias operation the prefix becomes our prefix when calling the package function, that is, F. Println ("Hello World").

_ Operation

This operation is often confusing for many people an operator, see the following import

Import (    "Database/sql"    _ "Github.com/ziutek/mymysql/godrv")

The operation is actually to introduce the package, instead of directly using the function inside the package, instead of invoking the INIT function inside the package.

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.