Что вернёт эта функция и как отложенное замыкание добирается до именованного возвращаемого значения?
Прочитайте фрагмент ниже. Функция использует именованное возвращаемое значение и отложенное замыкание, которое его изменяет.
Определите, какое значение вернёт increment(), и объясните, как отложенное замыкание добирается до именованного возвращаемого значения.
func increment() (result int) {
defer func() {
result++
}()
return 1
}
func main() {
fmt.Println(increment())
}
Определите вывод.
Вернёт 2. При именованном возвращаемом значении return 1 присваивает 1 переменной result, затем выполняется отложенное замыкание и увеличивает result до 2 перед фактическим возвратом. Отложенное замыкание может читать и менять именованные возвращаемые значения после return.
- ✗Думать, что
return 1окончателен и отложенное замыкание не может изменить результат - ✗Полагать, что это работает с безымянным возвратом — только именованное значение изменяемо из
defer - ✗Считать, что отложенное замыкание выполняется до присваивания выражения
return, а не после
- →Как этот приём используют, чтобы превратить
panicв возвращаемыйerror? - →Изменился бы результат, если бы возвращаемое значение было безымянным?
Что вернёт функция?
package main
import "fmt"
func increment() (result int) {
defer func() {
result++
}()
return 1
}
func main() {
fmt.Println(increment()) // 2
}
Вернёт 2. Возврат с именованным значением выполняется в два шага: return 1 сначала присваивает result = 1, и только потом запускаются отложенные вызовы. Замыкание видит ту же переменную result, увеличивает её до 2, и именно это значение получает вызывающий — после отложенных вызовов функция возвращает текущее result.
С безымянным возвратом (func() int) такой приём не сработал бы: возвращаемое значение копируется в момент return, и у отложенного замыкания нет доступа к нему. Этот приём — основа идиомы превращения panic в error через recover() внутри defer.