Вызов аргумента функции в куче внутри замыкания

Я использую ржавчину 0,8.

Почему я могу это сделать:

fn add(num: ~int) -> ~fn(int) -> int { |x|
    *num + x
}

но не это

fn outer(num: ~int) -> ~fn(int) -> int { |x|
    *inner(num) + x
}

fn inner(num: ~int) -> ~int {
    num
}

второй сбой с ошибкой: "ошибка: не может выйти из захваченной внешней переменной в закрытии кучи". Что делает вызов функции особенным?

Есть ли опасение, что внутренняя функция может сделать что-то грязное с этой коробочной функцией, которую статический анализ не уловит?

1 ответ

Решение

Проблема заключается в возможности дважды вызвать закрытие. При первом запуске захваченная переменная num перемещается в innerто есть вышли из среды замыкания. Затем, на втором звонке, место, где num был недействителен (так как он был удален), что нарушает безопасность памяти.

Более подробно, можно рассматривать замыкания как (приблизительно)

struct Closure { // stores all the captured variables
    num: ~int
}

impl Closure {
    fn call(&self, x: int) -> int { 
        // valid:
        *self.num + x

        // invalid:
        // *inner(self.num) + x
    }
}

Надеюсь, это проясняет ситуацию: в неверном каждый пытается двигаться self.num из-за заимствованного указателя в inner вызов (после чего он полностью отключен от num поле). Если бы это было возможно, то self будет оставлен в недопустимом состоянии, так как, например, деструктор на self.num возможно, был вызван, что освобождает память (нарушая безопасность памяти).


Одним из решений этого является "разовые функции", которые реализованы, но скрыты за флагом компилятора, так как они могут быть удалены в пользу (в самом основном) корректировки типа call выше, чтобы быть fn call(self, x: int)то есть вызывая ходы замыкания self а это значит, что вы можете выйти из окружающей среды (так как call затем владеет self и его поля), а также означает, что функция статически гарантированно будет вызвана только один раз *.

* Не совсем верно, если среда закрытия не переносит владение, например, если это было struct Env { x: int },

Другие вопросы по тегам