Можно ли использовать FnMut в переменной, которая не является изменяемой?

Функция принимает параметр типа FnMut, то есть этот параметр может изменять своё состояние. Почему тогда в сигнатуре функции event_handler не объявлен как mut? Документация утверждает, что мутабельный параметр необходим. В качестве примера приведена функция из winit:

```rust
pub fn run<F>(self, event_handler: F) -> Result<(), EventLoopError>
where
    F: FnMut(Event<T>, &EventLoopWindowTarget<T>),
{
    self.event_loop.run(event_handler)
}
```

Как объяснить отсутствие явного указания на мутабельность параметра event_handler?
  • 6 сентября 2024 г. 10:13
Ответы на вопрос 3
В Rust, когда мы говорим о "мутабельности" в контексте замыканий и типов, таких как `FnMut`, важно понимать, что мутабельность касается состояния замыкания, а не того, как мы передаем сам аргумент в функцию.

Когда вы передаете замыкание в функцию, вы не изменяете саму переменную, в которую оно заключено (в данном случае `event_handler`), вы просто передаете ее как аргумент функции. Поэтому сигнатура функции не требует, чтобы сам параметр `event_handler` был объявлен как `mut`. Однако важно то, что когда вы вызываете это замыкание (то есть когда вы вызываете `event_handler(...)` внутри функции), это замыкание может изменять своё внутреннее состояние, поскольку оно реализует трейт `FnMut`.

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

Пример использования `FnMut` выглядит так:

```rust
fn example<F>(mut handler: F)
where
    F: FnMut(),
{
    handler(); // Вызывая, мы можем менять состояние handler
}

// Использование
let mut count = 0;
let mut increase_count = || {
    count += 1;
};

example(increase_count); // Здесь `increase_count` может изменять `count`
```

В этом примере, передавая `increase_count` в `example`, переменная `handler` в `example` не помечена как `mut`, но внутри вызывается она как `FnMut`, что позволяет изменять состояние `count`.
Мутабельность нужна для вызова, так как FnMut вызывается по мутабельной ссылке. 
Здесь же только передаётся владение в метод run

P.S. что-то мне подсказывает, что сигнатура не совсем корректная. Отсутствует объявление дженерика T (и возможно его ограничений), отсутствует лайфтайм для ссылки в колбэке:
pub fn run<T, F>(self, event_handler: F) -> Result<(), EventLoopError>
    where
        F: for<'a> FnMut(Event<T>, &'a EventLoopWindowTarget<T>),
{
    self.event_loop.run(event_handler)
}
Потому что замыкание, которое не имеет мутабельных ссылок на окружение - автоматически реализует трейты Fn, FnMut и FnOnce. 

В функции run указан самый широкий вариант из возможных (Fn обычный был бы слишком узким, а FnOnce для run не подходит, тк замыкание предполагается вызывать много раз)

https://habr.com/ru/articles/588917/
https://stackoverflow.com/questions/30177395/when-...
Похожие вопросы