0

I have to pass a Arc<RwLock<&Fn()>> to a function:

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 Playground

Compilation fails with the error message:

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]>>`

Isn't the closure an Fn?

I have tried:

  • Replacing the Arc<RwLock> with a reference (resulting in &&Fn()). This only works when you remove one ampersand in the function signature of execute(), but that doesn't really help me, because for reasons I don't want to explain here, I need those wrappers. Rust Playground
  • Moving the Fn() in the execute() function signature into a where clause:

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

    That also works, but I cannot use a where clause either (because I would need it in a struct, but in structs there are no where clauses).

  • Combining the two previous ideas: Passing a Arc<RwLock<&&Fn()>> and removing one ampersand in the function signature. That would be what I need, but it also fails.
  • Casting wrapped_closure into an Arc<RwLock<&Fn()>> (this was the solution to a similar problem here). This fails as it's a "non-primitive cast"

Is it possible to pass an Arc<RwLock<&Fn()>> in Rust without adding a type parameter and a where clause? If yes, how?

trent
  • 25,033
  • 7
  • 51
  • 90
kangalio
  • 652
  • 8
  • 16
  • Welcome to Stack Overflow! I believe your question is answered by the answers of [https://stackoverflow.com/q/45159414/155423](https://stackoverflow.com/q/45159414/155423). TL;DR: `Box::new(&closure as &Fn())`. If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jun 19 '18 at 18:55
  • 1
    **`&closure as &Fn()`**, not the entire type. – Shepmaster Jun 19 '18 at 19:21
  • @Shepmaster. Okay, it works. But now I am passing just the &Fn() although execute() needs all the wrappers around it as well. Or did I misunderstand something? – kangalio Jun 19 '18 at 19:24
  • 1
    `let wrapped_closure = Arc::new(RwLock::new(&closure as &Fn()));` – Shepmaster Jun 19 '18 at 19:26
  • @Shepmaster *facepalm* I think it works now. Thanks a lot for the patience – kangalio Jun 19 '18 at 19:30
  • 1
    I think the `` was an incidental mistake, not part of the problem, so I removed it and edited the title to be more clear about the issue since I really don't think it's about `where` clauses at all. If you don't think my edits are true to the spirit of the original question, please feel free to edit it back. – trent Jun 20 '18 at 02:17

1 Answers1

3

The solution is by Shepmaster and taken from the comments.

The trick is to cast the closure reference to a &Fn, replacing Arc::new(RwLock::new(&closure)) with Arc::new(RwLock::new(&closure as &Fn())).

kangalio
  • 652
  • 8
  • 16