Меня смущает ключевое слово defer
, пока я изучаю golang
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()
}
почему результат равен нулю?
package main
func raisePanic() {
defer recover()
panic("boo")
}
func main() {
raisePanic()
}
почему все еще паника?
Большое спасибо.
Оба ваших вопроса вызваны одной и той же причиной, давайте объясним это с точки зрения исходного кода. Ключевая часть кода находится в normalizeGoDeferCall . Как описано в комментарии
normalizeGoDeferCall нормализует вызов в обычный вызов функции без аргументов и результатов, подходит для использования в OGO/ODEFER заявление. Когда компилятор анализирует ключевое слово
go
/defer
, выражение вызова с аргументами после них будет анализироваться как функция без аргументов, следовательно
defer f(x, y)
будет преобразован в
x1, y1 := x, y
defer func() { f(x1, y1) }()
Вернуться к вашим вопросам
defer handleErr(err)
будет преобразован в
err1 := err
defer func() { handleErr(err1) }()
err
оценивается, сохраняется заново и передается в handleErr
, так всегда будет nil
Правильный способ сделать это:
defer func() {handleErr(err)}()
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
, поэтому его можно восстановить.
Во второй части на этот вопрос есть ответ.