Есть ли что-то вроде finally() в Go, прямо противоположное тому, что init()?

Есть ли в Go что-то, что делает прямо противоположное тому, что init() делает внутри пакета?


person Prashant    schedule 04.06.2015    source источник


Ответы (1)


Это обсуждалось ранее командой Go, и вывод состоял в том, чтобы не добавлять поддержку. Цитируя minux:

Лично я предпочитаю стиль, в котором выход программы обрабатывается точно так же, как сбой программы. Я считаю, что как бы вы ни старались, ваша программа все равно может рухнуть в некоторых непредвиденных ситуациях; например, нехватка памяти может привести к падению любой хорошо работающей программы Go, и с этим ничего нельзя поделать; так что лучше дизайн для них. Если вы последуете этому, вы не почувствуете необходимости в очистке atexit (потому что, когда ваша программа выйдет из строя, atexit не будет работать, поэтому вы просто не можете полагаться на него).

Но у вас все еще есть несколько вариантов:

Обработка CTRL+C

Если вы хотите что-то сделать, когда ваша программа завершается с помощью CTRL+C (SIGINT), вы можете сделать это, см.:

Golang: Можно ли перехватить сигнал Ctrl+C и запустить функцию очистки в режиме отсрочки?

Финализатор объекта

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

Вы можете зарегистрировать такой финализатор с помощью runtime.SetFinalizer(), чего вам может быть достаточно, но обратите внимание:

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

См. этот пример:

type Person struct {
    Name string
    Age  int
}

func main() {
    go func() {
        p := &Person{"Bob", 20}
        runtime.SetFinalizer(p, func(p2 *Person) {
            log.Println("Finalizing", p2)
        })
        runtime.GC()
    }()

    time.Sleep(time.Second * 1)
    log.Println("Done")
}

Выходные данные (Go Playground):

2009/11/10 23:00:00 Finalizing &{Bob 20}
2009/11/10 23:00:01 Done
person icza    schedule 04.06.2015
comment
Я бы сказал, что (ab) использование финализаторов для очистки пользовательского пространства - это явный запах кода. Вместо этого следует разработать все приложение вокруг идеи управляемого завершения работы, а затем выполнять это управляемое завершение работы при соблюдении определенных условий (например, при получении SIGINT или SIGTERM). Это хорошая отправная точка. - person kostix; 04.06.2015
comment
см. также. - person kostix; 04.06.2015
comment
Я бы также добавил, что создание пакета, которому нужен хук atexit, вообще плохой дизайн. Пакет должен просто экспортировать что-то, что пользователь должен явно инициализировать и деинициализировать явно, а затем просто позволить пользователю сделать это — когда это действительно необходимо. - person kostix; 04.06.2015
comment
@kostix Я согласен, полагаться на такие функции - плохой дизайн, поэтому для них нет первоклассной поддержки. Просто показываю доступные варианты. - person icza; 04.06.2015