edit : Этот ответ неверный.Это останется здесь для потомков.
Давайте начнем с напоминания, почему Pin
был введен в первую очередь: мы хотим статически гарантировать, что фьючерсы с собственной ссылкой не могут быть перемещены, тем самым аннулируя их внутренние ссылки.
Имея это в виду, давайте посмотрим на определение Map
.
pub struct Map<Fut, F> {
future: Fut,
f: Option<F>,
}
Map
имеет два поля, первое хранит будущее, второе хранит закрытие, которое отображаетрезультат этого будущего в другую ценность.Мы хотим поддерживать хранение самоссылочных типов непосредственно в future
, не помещая их за указателем.Это означает, что если Fut
является самоссылочным типом, Map
не может быть перемещен после его создания.Вот почему мы должны использовать Pin<&mut Map>
в качестве приемника для Future::poll
.Если обычная изменяемая ссылка на Map
, содержащая самоссылочное будущее, когда-либо предоставлялась разработчиком Future
, пользователи могли бы заставить UB использовать только безопасный код, вызывая перемещение Map
с помощью mem::replace
.
Однако нам не нужно поддерживать хранение самоссылающихся типов в f
.Если мы предположим, что самоссылочная часть Map
целиком содержится в future
, мы можем свободно изменять f
, если мы не разрешаем перемещать future
.
Хотя самоссылочное закрытие будет очень необычным, предположение о том, что f
безопасно для перемещения (что эквивалентно F: Unpin
), нигде явно не указано.Однако мы по-прежнему перемещаем значение в f
в Future::poll
, вызывая take
!Я думаю, что это действительно ошибка, но я не уверен на 100%.Я думаю, что для f()
геттера должно потребоваться F: Unpin
, что означает, что Map
может реализовать Future
только тогда, когда аргумент закрытия безопасен для перемещения из-за Pin
.
Очень возможно, чтоЯ пропускаю некоторые тонкости в пин-API здесь, и реализация действительно безопасна.Я все еще оборачиваюсь вокруг этого.