Можно ли передать Arc‹RwLock‹&Fn()›› в функцию без использования параметра типа?

Мне нужно передать Arc<RwLock<&Fn()>> функции:

use std::sync::{Arc, RwLock};

fn main() {
    let closure = || println!("Hello World");
    let wrapped_closure = Arc::new(RwLock::new(&closure));
    execute(wrapped_closure);
}

fn execute(f: Arc<RwLock<&Fn()>>) {
    let rw_lock_read_guard = f.read().unwrap();
    (rw_lock_read_guard)()
}

Игровая площадка Rust

Компиляция завершается с ошибкой:

error[E0308]: mismatched types
 --> src/main.rs:6:13
  |
6 |     execute(wrapped_closure);
  |             ^^^^^^^^^^^^^^^ expected trait std::ops::Fn, found closure
  |
  = note: expected type `std::sync::Arc<std::sync::RwLock<&std::ops::Fn()>>`
             found type `std::sync::Arc<std::sync::RwLock<&[closure@src/main.rs:4:19: 4:45]>>`

Разве закрытие не Fn?

Я пытался:

  • Замена Arc<RwLock> ссылкой (в результате получается &&Fn()). Это работает только тогда, когда вы удаляете один амперсанд в сигнатуре функции execute(), но мне это не очень помогает, потому что по причинам, которые я не хочу здесь объяснять, мне нужны эти обертки. Игровая площадка Rust
  • Перемещение Fn() в сигнатуре функции execute() в предложение where:

    fn execute(f: Arc<RwLock<&F>>) where F: Fn() { /* ... */ }
    

    Это тоже работает, но я также не могу использовать предложение where (потому что оно мне понадобится в структуре, а в структурах нет предложений where).

  • Объединение двух предыдущих идей: передача Arc<RwLock<&&Fn()>> и удаление одного амперсанда в сигнатуре функции. Это было бы то, что мне нужно, но это также не удается.
  • Приведение wrapped_closure к Arc<RwLock<&Fn()>> (это было решением аналогичной проблемы здесь). Это не удается, поскольку это «непримитивный состав».

Можно ли передать Arc<RwLock<&Fn()>> в Rust без добавления параметра типа и предложения where? Если да, то как?


person kangalioo    schedule 19.06.2018    source источник
comment
Добро пожаловать в Stack Overflow! Я считаю, что на ваш вопрос ответили ответы https://stackoverflow.com/q/45159414/155423. TL;DR: Box::new(&closure as &Fn()). Если вы не согласны, измените свой вопрос, чтобы объяснить различия. В противном случае мы можем пометить этот вопрос как уже отвеченный.   -  person Shepmaster    schedule 19.06.2018
comment
&closure as &Fn(), а не весь тип.   -  person Shepmaster    schedule 19.06.2018
comment
@Шепмастер. Хорошо, это работает. Но теперь я передаю только &Fn(), хотя для execute() также нужны все обертки вокруг него. Или я что-то неправильно понял?   -  person kangalioo    schedule 19.06.2018
comment
@Shepmaster facepalm Думаю, теперь это работает. Большое спасибо за терпение   -  person kangalioo    schedule 19.06.2018
comment
Я думаю, что <F> была случайной ошибкой, а не частью проблемы, поэтому я удалил ее и отредактировал заголовок, чтобы лучше понять проблему, поскольку я действительно не думаю, что она вообще касается пунктов where. Если вы не считаете, что мои правки соответствуют духу исходного вопроса, пожалуйста, отредактируйте его обратно.   -  person trentcl    schedule 20.06.2018


Ответы (1)


Решение от Shepmaster взято из комментариев.

Хитрость заключается в том, чтобы привести ссылку замыкания к &Fn, заменив Arc::new(RwLock::new(&closure)) на Arc::new(RwLock::new(&closure as &Fn())).

person kangalioo    schedule 19.06.2018