Как вызовы закрытия в штучной упаковке работают так же, как вызовы закрытия?

#rust

#Ржавчина

Вопрос:

Почему вызов коробочных замыканий работает так же, как вызов замыканий? Это из-за Deref реализации Box? Будет ли это работать со всеми интеллектуальными указателями? Когда я попробовал несколько примеров, чтобы лучше понять это, я получил следующую ошибку.

 fn main() {
    let mut x = String::new();
    let y = || {
        let t = amp;mut x;
    };
    let mut ww = Box::new(y);
    (amp;mut ww)();
}
 

Это выдает ошибку

 error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
  --> src/main.rs:22:13
   |
22 |     let y = || {
   |             ^^ this closure implements `FnMut`, not `Fn`
23 |         let t = amp;mut x;
   |                      - closure is `FnMut` because it mutates the variable `x` here
...
26 |     (amp;mut ww)();
   |     ----------- the requirement to implement `Fn` derives from here
 

Любая документация о том, как работают коробочные закрытия, также была бы полезна.

Комментарии:

1. Да, это из-за реализаций Deref and DerefMut . Однако по причинам, которые не сразу очевидны для меня, компилятор, похоже, не выполняет изменяемое разыменование, а только неизменяемое разыменование (отсюда Fn FnMut и ошибка vs) в этом случае. Если вы принудительно разыменовываете изменяемые разыменования с помощью оператора deref as (amp;mut *ww)() , код компилируется.

Ответ №1:

Box реализует все функции FnX начиная с Rust 1.35 (подробнее здесь, источник), поэтому он должен быть вызываемым.

Похоже, что в этом конкретном случае компилятор недостаточно умен, чтобы удалить и преобразовать ваш тип, который amp;mut Box<Closure> , как ожидается Box<impl FnMut() -> ()> , будет выполнять вызов напрямую.

Это работает, хотя:

 (ww as Box::<dyn FnMut() -> ()>)();
 

И это тоже работает:

 ww.as_mut()()
 

Комментарии:

1. Это не совсем так. impl<Args, F, A> FnOnce<Args> for Box<F, A> реализация действительно существует. И если я преобразовал выше в объект trait Box<dyn FnOnce()> , приведенный выше пример будет работать так, как есть, без каких-либо deref.

2. Вы правы, спасибо, что указали, я обновил ответ.