Может ли рекурсивный вызов в defer быть оптимизирован компилятором? - PullRequest
3 голосов
/ 21 марта 2019

Допустим, у меня есть эта функция:

func abc(i int) (e error) {
    defer func() {
        if r := recover(); r != nil {
            abc(i * 2)
        }
    }()

    if someCondition(i) {
      return fmt.Errorf("Some Err");
    }

    return action() // returns err (nil in case of success) or panics
}

Будет ли это рассматриваться как рекурсивный вызов?Может ли он быть оптимизирован компилятором, так как хвостовые рекурсивные вызовы могут быть оптимизированы?

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

Ответы [ 2 ]

5 голосов
/ 21 марта 2019

Здесь нужно сказать две вещи:

  • recover() получит значение, переданное panic.В вашем случае, если someCondition не паникует, recover всегда будет возвращать ноль.Поэтому я не уверен, что вы пытаетесь сделать.
  • Go не выполняет оптимизацию хвостовых вызовов, команда go предпочитает значимые трассировки стеков.Есть обсуждения по этому поводу, но пока ничего не решено.

Если вы пытаетесь умножить i * 2 до тех пор, пока условие не станет истинным, то просто выполните:

// using recursion
func abc(i int) error {
    if err := someCondition(i); err != nil {
      return abc(i * 2);
    }
    return nil
}

// using loop
func abc(i int) error {
    for someCondition(i) != nil {
        i *= 2
    }
    return nil
}
2 голосов
/ 21 марта 2019

Будет ли это рассматриваться как хвост-рекурсивный вызов?

Нет.

Может ли он быть оптимизирован компилятором, так как могут быть оптимизированы хвостовые рекурсивные вызовы?

Количество

Не делай этого. Такая хитрость не устарела.

...