Оператор golang defer выполняется до или после оператора return? - PullRequest
0 голосов
/ 09 октября 2018

У меня есть вопрос о golang defer: Выполняется ли оператор golang defer до или после оператора return?

Я прочитал Defer_statements .Но я не получил ответа.

Я сделал простой тест:

func test1() (x int) {
    defer fmt.Printf("in defer: x = %d\n", x)

    x = 7
    return 9
}

func test2() (x int) {
    defer func() {
        fmt.Printf("in defer: x = %d\n", x)
    }()

    x = 7
    return 9
}

func test3() (x int) {
    x = 7
    defer fmt.Printf("in defer: x = %d\n", x)
    return 9
}

func main() {
    fmt.Println("test1")
    fmt.Printf("in main: x = %d\n", test1())
    fmt.Println("test2")
    fmt.Printf("in main: x = %d\n", test2())
    fmt.Println("test3")
    fmt.Printf("in main: x = %d\n", test3())
}

В test1(), используя Printf для печати x после отсрочки.В test2() используется анонимная функция для печати x после отсрочки.В test3(), используя Printf для печати x после отсрочки, но для отсрочки после x = 7.

Но результат таков:

test1
in defer: x = 0
in main: x = 9
test2
in defer: x = 9
in main: x = 9
test3
in defer: x = 7
in main: x = 9

Итак, любой может объяснить:1. почему получил этот результат?почему test1 печатает 0, test2 print9, test3 печатает 7. 2. Оправдывает ли оператор defer после возврата или до возврата?

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

Ответы [ 4 ]

0 голосов
/ 09 ноября 2018

Спасибо @ dev.bmax @ Tranvu Xuannhat @ rb16.С вашей помощью я нашел ключевое объяснение из Defer_statements .

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

Мы можем разбить defer ... на три части.

  1. вызвать defer, оценив значение параметра функции.
  2. выполнить defer, нажавфункция в стеке.
  3. выполнение функций в стеке после возврата или паники .

Я сделал новый test4 для объяснения.

func test4() (x int) {
    defer func(n int) {
        fmt.Printf("in defer x as parameter: x = %d\n", n)
        fmt.Printf("in defer x after return: x = %d\n", x)
    }(x)

    x = 7
    return 9
}

В test4,

  1. вызывает defer, оценивая значение n , n = x = 0 , поэтому x в качестве параметра равно 0.
  2. выполнить отсрочку, поместив func(n int)(0) в стек.
  3. выполнить func(n int)(0) после return 9, n в fmt.Printf("in defer x as parameter: x = %d\n", n) будет оценено, x в fmt.Printf("in defer x after return: x = %d\n", x) будет оценено, x -9。

Итак, получил результат:

test4
in defer x as parameter: x = 0
in defer x after return: x = 9
in main: x = 9
0 голосов
/ 09 октября 2018

Я буду ссылаться на Defer_statements , чтобы объяснить ваши результаты.

Вопрос 2: Задержка выполняется после возврата.

Вопрос 1: Из документов

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

  • Тест 1: Defer вызывает fmt.Println.fmt.Println оценивает значение x, которое равно 0 (нулевое значение).test1 () возвращает 9 в основной функции.

  • Тест 2: Defer вызывает func () {}.fmt.Println вычисляет x только при выполнении func () {} (после возврата).Следовательно, x оценивается как 9. test2 () возвращает 9 в основной функции.

  • Тест 3: Defer вызывает fmt.Println.fmt.Println оценивает значение x, которое равно 7 (x назначено 7).test3 () возвращает 9 в основной функции.

0 голосов
/ 09 октября 2018

Это не до или после, это все о том, присутствует оператор defer в стеке или нет.если это так (если элемент управления достигает оператора defer, он сохраняет оператор сохраняет в стек), то после того, как он будет выполнен после оператора return.

, например -

func testing() err {
    x, err := doSomething();
    if err != nil {
       return;
    }
    defer fmt.Println("hello")
    return nil
}

Такесли err != nil эта отсрочка никогда не будет выполнена, потому что программа вернулась до того, как элемент управления достигнет оператора defer.

Теперь перейдем к вашему Вопросу (все дойдут до оператора defer) 1. case, оператор сохранен встек равен defer fmt.Printf("in defer: x = %d\n", x) (с нулевым значением x)

case - оператор, хранимый в стеке: Функция

defer func() { fmt.Printf("in defer: x = %d\n", x) }()

, которая зависит от x (Примечание в стеке откладываетоператор является функцией, и значение функции будет назначено во время выполнения функции)

Кейс - defer fmt.Printf("in defer: x = %d\n", x) со значением 7
0 голосов
/ 09 октября 2018

В тесте first значение параметра x оценивается при выполнении строки, содержащей defer.И это происходит в строке 1, когда x по-прежнему равно 0.

Обратите внимание, что, хотя fmt.Printf будет вызываться позже, его параметры оцениваются заранее.

В третий тест, значение параметра x устанавливается в 7 до выполнения оператора defer.Опять же, это происходит до фактического вызова fmt.Printf.

второй тест немного отличается.Переменная x входит в сферу действия анонимной функции.Это значение оценивается при запуске функции, что происходит при возврате тестовой функции.К этому времени x равно 9.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...