[Basics of Go combat] How does Go catch and handle exceptions

Hits: 0

Table of contents

1. Introduction

2. Data structure

1、defer

2、panic

3、recover

Three, rookie combat

1. Create g007.go

2. Compile and run

3. Running results

1. Introduction

The Go language pursues simplicity and elegance, and does not support the traditional try-catch-final approach to capture and handle exceptions. The designers of the [Go language] believe that mixing exceptions with control structures will easily make the code more confusing.

In Go, use multivalued returns to return errors, don’t use exceptions instead of errors, and don’t use them to control flow.
In the case of real exceptions (such as division by 0), Exception processing is used.

Go uses the panic / recover pattern to handle errors. panic can be raised anywhere, but recover is only valid in the function called by defer.

2. [Data structure]

1、defer

The defer statement puts a function into a list (more accurately represented by the stack) whose functions are executed when the function surrounding the defer returns.

// defer data structure 
type _defer struct {

    siz int32       // memory size of parameters and results 
    started    bool        // whether defer executes 
    heap       bool        // whether it is on the heap 
    openDefer bool        // whether the current defer is optimized by open coding 
    sp uintptr     // stack pointer 
    pc uintptr     // caller's Program counter 
    fn *funcval    // function passed in defer keyword 
    _panic *_panic     // structure that triggers delayed call, may be empty 
    link *_defer     // points to defer linked list

}

defer is usually used to simplify various cleanup actions of functions, such as closing files, unlocking, etc. to release resources.

2、panic

panic is a built-in function to stop control flow, which is equivalent to throw exception in other programming languages. When the function F calls panic, the execution of F will be stopped, the defer operations defined before panic in F will be executed, and then the F function will return.
For the caller, the behavior of calling F is like calling panic (if the panic is not recovered inside the F function), if the panic is not captured, it is equivalent to a layer of panic, and the program will crash. panic can be called directly, or it can be caused by a program runtime error, such as an array out of bounds, etc.

// panic data structure 
type _panic struct {
    argp       unsafe .Pointer     // Pointer to the parameter when defer is called 
    arg        interface {}        // The parameter passed in when calling panic 
    link *_panic            // Points to the earlier called panic structure 
    recovered bool               // Indicates whether the current panic is recovered by recovery 
    aborted    bool               // Indicates whether the current panic is forcibly terminated
    pc        uintptr
    sp        unsafe.Pointer
    goexit    bool
}

The three fields of pc, sp and goexit in the structure are all introduced to fix the problem of runtime.Goexit. This function can only end the Goroutine that calls the function without affecting other Goroutines, but the function will be canceled by panic and recover in defer. The purpose of introducing these three fields is to solve this problem.

3、recover

recover is a built-in function to recover from panic, and recover can only play a real role in the function of defer. In the normal case (no panic occurred), calling recover will return nil and have no effect. If the current goroutine panics, the call to recover will capture the value of panic and resume normal execution.

Three, rookie combat

Practical Requirements: How Go Catches and Handles Exceptions

Schedule now!

1. Create g007.go

/*
 * @Author: rookie combat
 * @FilePath: /go110/go-007/g007.go
 * @Description: crashes and exceptions, defer, panic, recover
 */

package main

import (
    "fmt"
    "runtime"
)

// test recovery 
func test_recover () {
     // Use defer + recover to catch and handle exceptions 
    // Called in anonymous function form: func(){}() 
    defer func () {
        err := recover() // the recover built-in function catches an exception 
        if err != nil {   // nil is the zero value of err 
            fmt.Println( "err = " , err)
             //runtime error: index out of range [3] with length 3
        }
    }()
    arr := []string{"a", "b", "c"}
    str := arr[3]
    fmt.Println("str = ", str)
}

/**
    Panic will usually cause the program to hang (unless recover), and then the Go runtime will print out the call stack
    However, the key point is that even if the function panics when it is executed, the function does not go down, and the runtime does not immediately pass the panic up.
    Instead, go to the defer, wait for the defer things to run out, and then pass the panic up.
    So defer is somewhat similar to finally in try-catch-finally.
**/
func test_panic() {
     // Declare defer first, catch panic exception 
    // Calling method of anonymous function: func(){}() 
    defer func () {
        if err := recover(); err != nil {
            fmt.Println( "Caught exception from panic: " , err)
            fmt.Println( "Caught the exception of panic, recover it back." )
        }
    }()

    // If you don't write, it will report expression in defer must be function call 
    panic( "An exception is thrown, defer will catch the exception through recover, and the subsequent program will run normally." )

    fmt.Println( "This will not be executed" )
}

func main() {
     // use the built-in function to print 
    println( "Hello" , "Rookie combat" )

    // test recovery
    test_recover()

    // test panic
    test_panic()

    // current version 
    fmt.Printf( "Version: %s \n" , runtime.Version())
}

2. Compile and run

1. The generated module depends on

go mod init g007

2. Compile

go build g007.go 

3. The compiled directory structure

└── go-007
    ├── g007
    ├── g007.go
    └── go.mod

4. Run

go run g007

3. Running results

Hello rookie combat
err = runtime error: index out of range [3] with length 3
The exception generated by panic is caught: an exception is thrown, defer will catch the exception through recover, and the subsequent program will run normally.
Catch the exception of panic, recover to recover.
Version: go1.17.10 

Be a rookie, keep learning!

You may also like...

Leave a Reply

Your email address will not be published.