Непонятно, что происходит с отложенной обработкой ошибок и отложенным восстановлением в процессе работы

Меня смущает ключевое слово defer, пока я изучаю golang

  1. отложить обработку ошибок
package main

import (
    "errors"
    "fmt"
)

func handleErr(err error) {
    fmt.Println(err)
}

func returnErr() (err error) {
    defer handleErr(err)

    return errors.New("boo")
}

func main() {
    returnErr()
}

почему результат равен нулю?

  1. отложить восстановление
package main

func raisePanic() {
    defer recover()

    panic("boo")
}

func main() {
    raisePanic()
}

почему все еще паника?

Большое спасибо.

🤔 А знаете ли вы, что...
Go компилируется в машинный код, что делает его очень быстрым.


50
1

Ответ:

Решено

Оба ваших вопроса вызваны одной и той же причиной, давайте объясним это с точки зрения исходного кода. Ключевая часть кода находится в normalizeGoDeferCall . Как описано в комментарии

normalizeGoDeferCall нормализует вызов в обычный вызов функции без аргументов и результатов, подходит для использования в OGO/ODEFER заявление. Когда компилятор анализирует ключевое слово go/defer, выражение вызова с аргументами после них будет анализироваться как функция без аргументов, следовательно

defer f(x, y)

будет преобразован в

x1, y1 := x, y
defer func() { f(x1, y1) }()

Вернуться к вашим вопросам

  1. отложить обработку ошибок
defer handleErr(err)

будет преобразован в

err1 := err
defer func() { handleErr(err1) }()

err оценивается, сохраняется заново и передается в handleErr, так всегда будет nil

Правильный способ сделать это:

defer func() {handleErr(err)}()
  1. отложить восстановление у восстановления вроде нет аргументов, но оно связано с реальной реализацией gorecover, чтобы оно было преобразовано в
argp := getcallersp()
defer func(){
    gorecover(argp)
}()
    if p != nil && !p.goexit && !p.recovered && argp == uintptr(p.argp) {
        p.recovered = true
        return p.arg
    }

Его можно восстановить, если два argp равны, но, очевидно, это не так. Если мы изменим это следующим образом:

func raisePanic() {
    defer func() {
        recover()
    }()

    panic("boo")
}

argp — это функция, зарегистрированная путем вызова defer после того, как в этом случае произойдет panic. Эта функция вызывается gopanic. Следовательно, argp — это sp функции gopanic. Он рассчитывается и передается в gorecover. После сравнения gorecover считает argp равным p.argp, поэтому его можно восстановить.