Как вернуть значение в паникующей функции Go?

Ожидается, что функция My Go вернет значение, но может вызвать панику при вызове библиотечной функции. Я могу использовать recover() для захвата этого в отложенном вызове, но как я могу вернуть значение в этом случае?

func MyFunc() string{
    defer func() {
        if err := recover(); err != nil {
            // What do I do to make MyFunc() return a value in case of panic?
        }
    }()
    SomeFuncThatMayPanic()
    return "Normal Return Value"
    // How can I return "ERROR" in case of panic?
}

person NeoWang    schedule 16.10.2015    source источник


Ответы (2)


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

Пример:

func main() {
    fmt.Println("Returned:", MyFunc())
}

func MyFunc() (ret string) {
    defer func() {
        if r := recover(); r != nil {
            ret = fmt.Sprintf("was panic, recovered value: %v", r)
        }
    }()
    panic("test")
    return "Normal Return Value"
}

Вывод (попробуйте на Go Playground):

Returned: was panic, recovered value: test

Это упоминается в Spec: инструкции Defer:

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

Это также упоминается в сообщении блога Отсрочка, паника и восстановление< /а>:

Отложенные функции могут считывать и присваивать именованные возвращаемые значения возвращаемой функции.

А также в Effective Go: Recover:

Если doParse вызывает панику, блок восстановления установит возвращаемое значение равным nil — отложенные функции могут изменять именованные возвращаемые значения.

person icza    schedule 16.10.2015
comment
Меня интересовало, что было бы возвращено, если бы не было именованных возвращаемых значений. Играя с вашей игровой площадкой, похоже, что это нулевое значение типа - person Kyle Chadha; 26.09.2017
comment
@KyleChadha Да, если результаты не названы и оператор return не достигнут (например, из-за паники), возвращаются нулевые значения типов результатов. Это подробно описано в Почему обычный возврат может скрывать панику, которую именованный возврат правильно предоставляет вызывающей стороне? - person icza; 26.12.2019

Используя пример в ответе icza, и если вам интересно, что произойдет, если вы оправитесь от паники, но не присвоите значение для именованного возврата, например:

func main() {
    fmt.Println("Returned:", MyFunc()) // false
}

func MyFunc() (ret bool) {
    defer func() {
        if r := recover(); r != nil {
        }
    }()
    panic("test")
    return true
}

Функция вернет нулевое значение указанного возвращаемого типа.

Запустите пример на Игровой площадке Go.

person Carlos Fuentes    schedule 09.05.2019