Go -- operation, process control (if, for, switch, goto, defer) exception mechanism (panic, recover)

Posted by amazinggrace1983 on Wed, 15 Dec 2021 00:35:34 +0100

V Arithmetic operation


Logic and

0 && 0 =1
1 && 1 =1
1 && 0 =0

Logical or

0 || 0 =0
0 || 1 =1 
1 || 0 =1
1 || 1 =1

Relational operation: the result is also true and false

Arithmetic operator

   + ,- ,* ,/ ,% 

Self increment: + +, which can only be used for variables and can only be placed later
Self subtraction: –

Assignment operation

== ,!= ,> , >= , < ,<=

The result is a Boolean bool

Bit operation

That is, binary operation

&And operation, the same is 1, the difference is 0
|Or operation, with 1, is 1
^And or, the difference is 1
&^Clear by bit, and clear the positions that are all 1

Move left < <, into 2
Move right > >, divide by 2

Assignment operation

= , +=, -=, *=, /= , %=, ,|= ,&= ,^= , &^= , <<= , <<=

Type conversion

  1. Different types cannot operate without any operation
  2. From large to small, overflow may occur

Cast type

var A int =3
var B uint =4
fmt.Println(A+ int(B))

Vi Process control

1 . Conditional statement if else

&&Both sides should be satisfied
||There is a satisfaction

if condition {

} else if condition{

} else{

}
	var yes string
	fmt.Scan(&yes)
	if yes == "Y" || yes == "y"{
		fmt.Println("ok")
	} else{
		fmt.Println("error")
	}

2 . Select the statement switch

There are two main uses

  1. Single value, matching variables
  2. Expressions for comparison
  3. case can be followed by multiple conditions
  4. Penetrate the fallthrough. Adding the fallthrough after the case statement block will continue to execute the next case
switch variable {
# Value, which can be multiple
case value :
	Statement 1
case value ;
	Statement 2
default:
	Statement 3
}

Single value, matching

var yes string
	fmt.Scan(&yes)
	switch yes {
	case "y","Y":
		fmt.Println("ok")
	default:
		fmt.Println("no")
	}

Expressions for comparison

switch{
case A>=90:
	fmt.Println("A")
case A>=80:
	fmt.Println("A")
}

Match type

var x interface{} //x is an empty interface type and can receive any type
    var y = 19.9
    x = y
    switch i := x.(type) {
    case nil:
        fmt.Printf("x The type of is%T\n", i)
    case float64:
        fmt.Printf("x The type of is%T\n", i)
    default:
        fmt.Println("unknown type")
    }

Switchable function

switch can be followed by a function, as long as the value type after case is consistent with the return value of the function.

import "fmt"

// A function to judge whether a student has failed in the course
// The return value is Boolean
func getResult(args ...int) bool {
    for _, i := range args {
        if i < 60 {
            return false
        }
    }
    return true
}

func main() {
    chinese := 80
    english := 50
    math := 100

    switch getResult(chinese, english, math) {
    // case must also be Boolean
    case true:
        fmt.Println("The student passed all his grades")
    case false:
        fmt.Println("The student has a failed record")
    }
}

switch can not receive expression

No variables, expressions or functions can be connected after switch.

When nothing is received, switch - case is equivalent to if - else if - else

score := 30

switch {
    case score >= 95 && score <= 100:
        fmt.Println("excellent")
    case score >= 80:
        fmt.Println("good")
    case score >= 60:
        fmt.Println("qualified")
    case score >= 0:
        fmt.Println("unqualified")
    default:
        fmt.Println("Incorrect input...")
}

3 . Loop statement for

Mode 1

source :=0
//Post initial condition
for i:=1 ; i <=100 ; i++{
	source +=i
}
fmt.Println(source)

Mode II

source =0
i :=1
for i <=100 {
	source +=i
	i++
}

Mode 3: dead cycle

var  i int =0
for{
	fmt.Println(i)
	i++
}

Method 4: string, array, slice, map, pipeline
Traversing an iteratable object,
range can be followed by array, slice, string, etc

Return two values: index and data. If you can't use the index in the following code, you need to use it_ express.

	name :="Handsome"
	//Index i, character ch name string
	for i,ch := range name{
		fmt.Println(i,ch)
	}

Placeholder "_"

	name :="Handsome"
	//Index i, character ch name string
	for _,ch := range name{
		fmt.Println(ch)
	}

4. Closing statement

  1. continue
    Skip this cycle

  2. break
    Break label jumps out of the loop. You can jump out of the multi-layer loop as follows

END
for i :=1 ;i<=100 ;i++{
	break END
}
  1. return is used in a method or function to indicate the method or function where the termination occurs (method and function)
    return in the main function, it means to terminate the main function and terminate the program
for i := 0; i <= 10; i++ {
        if i == 5 {
            return //Exit the main function directly
        }
        fmt.Printf("Number of cycles:%d\n", i)
    }
    //I'll never take it here. On the fifth for loop, I directly return
    fmt.Println("The cycle ended and came to me")

5. Jump to goto

goto
Label: capitalized English letters, placed on the far left

You can jump out of multi-layer loops at one time

goto label A

label A:


Implementing for loop with jump

There must be no variable declaration between goto statement and label, otherwise compilation error will occur

.\main.go:7:7: goto flag jumps over declaration of say at .\main.go:8:6

6. defer deferred statement

1. Delayed call

Followed by a function call, you can delay the call of xxx function until the current function is executed.

defer xxx()
import "fmt"

func myfunc() {
    fmt.Println("B")
}

func main() {
    defer myfunc()
    fmt.Println("A")
}

//The output is as follows
A
B
import "fmt"

func main() {
    defer fmt.Println("B")
    fmt.Println("A")
}

2. Snapshot of variables evaluated immediately

Using defer only delays calling the function. At this time, the variables passed to the function should not be affected by subsequent programs.

For example, here's an example

import "fmt"

func main() {
    name := "go"
    defer fmt.Println(name) // Output: go

    name = "python"
    fmt.Println(name)      // Output: python
}

// output
python
go

It can be seen that when name is reassigned to python, the unassigned variable value is still used in subsequent calls to defer. Fortunately, here in defer, all this is the same as taking a snapshot.

If defer is followed by an anonymous function, the situation will be different. Defer will get the last variable value

package main

import "fmt"


func main() {
    name := "go"
    defer func(){
    	fmt.Println(name) // Output: python
	}()
    name = "python"
    fmt.Println(name)      // Output: python
}

3. Multiple defer s are called in reverse order

When we use multiple defers in a function, what are the execution functions of these defers?

import "fmt"

func main() {
    name := "go"
    defer fmt.Println(name) // Output: go

    name = "python"
    defer fmt.Println(name) // Output: python

    name = "java"
    fmt.Println(name) //Output: java
}

//output
java
python
go

The output is as follows. It can be seen that multiple defer s are called in reverse order, which is a bit similar to the stack. Last in first out.

4. The order of defer and return

Which of defer and return is called first?

import "fmt"

var name string = "go"

func myfunc() string {
    defer func() {
        name = "python"
    }()
    fmt.Printf("myfunc In function name: %s\n", name)
    return name
}

func main() {
    myname := myfunc()
    fmt.Printf("main In function name: %s\n", name)
    fmt.Println("main In function myname: ", myname)
}

//output
myfunc In function name: go
main In function name: python
main In function myname:  go

The first line name is still a global variable, and the value is still go

The second line is not difficult to understand. When the global variable is changed in defer, the value of name has become python

In the third line, defer is called after return. Therefore, myname has been assigned to go before defer is executed.

5. Why is there a defer?

Just put the function executed by defer in return.

However, when there are multiple return s in a function, you have to call the function many times, and the code becomes bloated.

No defer

func f() {
    r := getResource()  //0, get resources
    ......
    if ... {
        r.release()  //1. Release resources
        return
    }
    ......
    if ... {
        r.release()  //2. Release resources
        return
    }
    ......
    if ... {
        r.release()  //3. Release resources
        return
    }
    ......
    r.release()     //4. Release resources
    return
}

After using defer, the code is simple and direct. No matter where you return, the function after defer will be executed.

func f() {
    r := getResource()  //0, get resources

    defer r.release()  //1. Release resources
    ......
    if ... {
        ...
        return
    }
    ......
    if ... {
        ...
        return
    }
    ......
    if ... {
        ...
        return
    }
    ......
    return
}

7. Exception mechanism: panic and recover

  • panic: throw an exception to crash the program

  • Recover: catch exceptions, recover programs or finish work

After revocer is called, the thrown panic will end here and will not be thrown out. However, recover cannot be used arbitrarily. It has mandatory requirements and must be used under defer.

1. Trigger panic

Manually triggering downtime is a very simple thing. You only need to call the built-in function panic

package main

func main() {
    panic("crash")
}

After operation, the system will report errors and downtime directly

$ go run main.go
go run main.go
panic: crash

goroutine 1 [running]:
main.main()
        E:/Go-Code/main.go:4 +0x40
exit status 2

2. recover for capturing panic

When an exception occurs, you sometimes have to catch it

This leads to another built-in function - recover, which allows the program to regenerate after downtime.

However, there is a condition for the use of recover, that is, it must be in the defer function to take effect. Under other scopes, it does not work.

import "fmt"

func set_data(x int) {
    defer func() {
        // recover() can print the captured panic information
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()

    // Deliberately create array out of bounds and trigger panic
    var arr [10]int
    arr[x] = 88
}

func main() {
    set_data(20)

    // If this sentence can be executed, panic is captured
    // Subsequent programs can continue to run
    fmt.Println("everything is ok")
}

After operation

$ go run main.go
runtime error: index out of range [20] with length 10
everything is ok

Generally speaking, we should not deal with the programs that enter panic downtime, but sometimes we need to recover from the downtime. At least we can do some operations before the program crashes,
When the web server encounters unexpected serious problems, all connections should be closed before the crash. If nothing is done, the client will always be waiting. If the web server is still in the development stage, the server can even feed back the exception information to the client to help debugging.

3. Unable to cross collaboration process

Even if panic will cause the whole program to exit, if there is a defer delay function before exiting, you still have to execute defer.

However, this defer has no effect among multiple coroutines. Triggering panic in a child coroutine can only trigger the defer in its own coroutine, rather than calling the defer function in the main coroutine.

import (
    "fmt"
    "time"
)

func main() {
    // This defer does not execute
    defer fmt.Println("in main")

    go func() {
        defer println("in goroutine")
        panic("")
    }()

    time.Sleep(2 * time.Second)
}


//The output is as follows
in goroutine
panic:

goroutine 6 [running]:
main.main.func1()
        E:/Go-Code/main.go:12 +0x7b
created by main.main
        E:/Go-Code/main.go:10 +0xbc
exit status 2

practice

Output a number from bits, tens and hundreds
thinking

Hundredth: n/100%10
 Ten: n/10%10
 Bit: n/1%10

code

package main

import "fmt"

func main() {
	var n,s int
	fmt.Scan(&n)
	if n>=999 {
		s =4
	} else if n>99{
		s =3
	}else if n>9{
		s=2
	}else {
		s=1
	}

	for i:=1;i<=s;i++{
		// l is 10 *i
		l :=1
		for j:=2;j<=i;j++{
			l *=10
		}

		fmt.Println(n/l%10)
	}
}

Multiple login

package main

import "fmt"

func main() {
	var name,pwd string
	//Limit: login can only be repeated three times,
	var logincache=3
	for i :=1;i<=3;i++{
		fmt.Println("enter one user name")
		fmt.Scanln(&name)
		fmt.Println("Please input a password")
		fmt.Scanln(&pwd)
		if name == "qcq" && pwd == "qcq123" {
			fmt.Println("Welcome to the glory of the king!")
			break
		}else {
			logincache--
			fmt.Printf("Input error, you still have%d Second chance\n",logincache)
		}
	}
}

Output a square line

Calculate the sum of all odd numbers within 100

func main() {
	i :=1
	num :=0
	for i<=100{
		num +=i
		i+=2
	}
	fmt.Println(num)
}

Grade students' grades

func main() {
	var n int
	fmt.Scanln(&n)
	switch{
	case n>=90:
		fmt.Println("A")
	case n>=80:
		fmt.Println("B")
	case n>60:
		fmt.Println("C")
	default:
		fmt.Println("You are so stupid.")
	}
}

Print into a formula table

func main() {
	for i :=1;i<=9;i++{
		for j:=1;j<=i;j++{
			fmt.Printf("%d*%d=%d\t",j,i,i*j)
		}
		fmt.Println()
	}
}

Guess the number, generate a number, and let the user guess five times
And each time give the user a prompt, size, and several more opportunities
Re challenge

Topics: Go