13. Механизм исключения языка Go: паника и восстановление

Go

Привет всем, меня зовут Мин.

В период самостоятельного изучения Golang я написал подробные учебные заметки и разместил их в своем личном общедоступном аккаунте WeChat «Время программирования на Go».Что касается языка Go, я тоже новичок, поэтому то, что я написал, должно больше подходить для новых студентов, если вы только изучаете язык Go, вам стоит обратить на него внимание, учиться и расти вместе.

Мой онлайн-блог:golang.iswbm.comМой Github: github.com/iswbm/GolangCodingTime


Языки программирования обычно имеют механизмы отлова исключений, в Python они используютсяraiseиtry-exceptЗаявление для реализации генерации и перехвата исключений.

В Golang есть много распространенных ошибок, о которых можно предупредить заранее на этапе компиляции, таких как синтаксические ошибки или ошибки типов, но некоторые ошибки могут возникнуть только после запуска программы, например, доступ к массиву за пределами границ, нулевой указатель ссылки и т. д. Ошибка времени приведет к выходу из программы.

Конечно, тот, кто может вызвать сбой и выход программы, также может быть нами самими.Например, после проверки и принятия решения о том, что текущая среда не может соответствовать ожидаемым условиям нашей программы (например, назначенный прослушивающий порт службы заняты другими программами), мы можем вручную вызвать панику, чтобы программа завершила работу и перестала работать.

1. Вызвать панику

Запуск простоя вручную очень прост, достаточно вызвать встроенную функцию panic, вот так

package main

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

После запуска сразу сообщает об ошибке и вылетает

$ 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. Поддаться панике

Возникает исключение, и иногда его приходится перехватывать, как в Python.exceptТо же самое, как это делается в Голанге?

Это должно привести к другой встроенной функции --recover, что позволяет программе вернуться к жизни после сбоя.

Тем не менее, использование восстановления имеет условие, что оно должно быть в функции отсрочки, чтобы оно вступило в силу.В других областях это не работает.

Вот простой пример

import "fmt"

func set_data(x int) {
    defer func() {
        // recover() 可以将捕获到的panic信息打印
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()

    // 故意制造数组越界,触发 panic
    var arr [10]int
    arr[x] = 88
}

func main() {
    set_data(20)

    // 如果能执行到这句,说明panic被捕获了
    // 后续的程序能继续运行
    fmt.Println("everything is ok")
}

После запуска вывод следующий

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

Вообще говоря, вы не должны ничего делать с программой, которая попадает в панику, но иногда нам нужно иметь возможность восстановиться после сбоя, по крайней мере, мы можем что-то сделать до того, как программа выйдет из строя, например, когда веб-сервер сталкивается с В случае непредвиденных серьезных проблем все соединения должны быть закрыты до сбоя.Если ничего не делать, клиент будет находиться в состоянии ожидания.Если веб-сервер все еще находится в стадии разработки, сервер может даже вернуть информацию об исключении в клиент., чтобы помочь с отладкой.

3. Нельзя пересекать сопрограммы

Из приведенного выше примера вы можете видеть, что даже если паника приведет к выходу всей программы, если перед выходом есть функция задержки отсрочки, отсрочка должна быть выполнена.

Но эта отсрочка не действует между несколькими сопрограммами.Когда паника запускается в подпрограмме, она может вызвать отсрочку только в своей собственной сопрограмме, но не может вызвать функцию отсрочки в основной сопрограмме.

Давайте проведем эксперимент.

import (
    "fmt"
    "time"
)

func main() {
    // 这个 defer 并不会执行
    defer fmt.Println("in main")

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

    time.Sleep(2 * time.Second)
}

Вывод выглядит следующим образом

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

4. Подведите итоги

Генерация и перехват исключений Golang зависят от двух встроенных функций:

  • паника: генерирует исключение, вызывая сбой программы
  • восстановить: поймать исключение, восстановить программу или сделать последние штрихи

После вызова revocer брошенный panic будет завершен здесь и больше не будет выкинут, однако, recovery нельзя использовать произвольно, оно имеет обязательные требования и может использоваться только под defer.

Руководство по серии

01. Построение среды разработки (Goland & VS Code)

02. Изучите пять методов создания переменных

03. Подробные типы данных:**Целое число и число с плавающей запятой**

04. Подробные типы данных: байт, руна и строка

05. Подробно объясните типы данных: массивы и срезы

06. Подробно объясните типы данных: словари и логические значения

07. Подробно объясните типы данных: указатели

08. Объектно-ориентированное программирование: структуры и наследование

09. Статья для понимания функций в Go

10. Управление потоком языка Go: условный оператор if-else

11. Управление потоком языка Go: оператор выбора switch-case

12. Управление потоком языка Go: оператор цикла for

13. Перейти к управлению языковым потоком: перейти к безусловному переходу

14. Перейти к управлению языковым потоком: отложить отложенный вызов

15. Объектно-ориентированное программирование: интерфейсы и полиморфизм

16. Ключевые слова: В чем разница между make и new?

17. Статья о понимании блоков и области видимости в Go

18. Изучите Go Coroutines: горутины

19. Изучите сопрограммы Go: подробно объясните каналы/каналы

20. Подробное объяснение нескольких классических случаев ошибки взаимоблокировки канала.

21. Изучите сопрограммы Go: группа ожидания

22. Изучите процедуры Go: мьютексы и блокировки чтения-записи

23. Обработка исключений в Go: паника и восстановление

24. Сверхдетальная интерпретация прошлой жизни Go Modules и вводное использование

25. 8 важных знаний об импорте пакетов на языке Go

26. Как открыть исходный код модулей, которые я написал для использования другими?

27. Расскажите об утверждениях типов в Go?

28. Эти пять пунктов помогут вам понять, как использовать select в языке Go.