Reputation: 223
I am using a trait to create an alias for a closure so that I do not have to repeat the declaration several times throughout the code, however I cannot work out how to cast the trait back to Fn so that I can call it in main, is this possible?
trait Closure: Send + Sync {}
impl <F: Send + Sync> Closure for F where F: Fn(&str) -> bool {}
pub struct Struct {
pub closure: Box<dyn Closure>
}
impl Struct {
pub fn new(closure: impl Closure + 'static) -> Self {
Self{
closure: Box::new(closure)
}
}
}
pub fn main() {
let s = Struct::new(|f: &str| f.is_empty());
let result: bool = (s.closure)("hello world"); //TODO
println!("{}", result );
}
Upvotes: 4
Views: 231
Reputation: 43753
As Ibraheem Ahmed's answer points out, Closure
doesn't guarantee in general that any type implementing it is a function. But you can do that by adding Fn
as a supertrait:
pub trait Closure: Send + Sync + Fn(&str) -> bool {}
With this one line changed, your code will compile and run.
The difference between this and the other option of adding an explicit call
method to the trait is here, Closure
can only be implemented for closures and function pointers — not for structs or enums — because in stable Rust (as of version 1.47.0) there is no way to write an impl Fn for MyType
. But if you only intend to use this trait with actual closures like |f: &str| f.is_empty()
, that's no problem.
Upvotes: 3
Reputation: 13518
You are trying to call a Box<dyn Closure>
as a method. At that point, all the compiler knows about this type is that it implements Closure
. It does not know if it is a function, a struct, or anything else, which is why your code will not compile.
You can get solve this by adding an associated method to the Closure
trait. This is a very common way of modelling functions:
pub trait Closure: Send + Sync {
fn call(&self, input: &str) -> bool;
}
You can implement it for the Fn
type:
impl <F: Send + Sync> Closure for F where F: Fn(&str) -> bool {
fn call(&self, input: &str) -> bool {
self(input)
}
}
And call the Closure
trait object by simply invoking its call
method:
let s = Struct::new(|f: &str| f.is_empty());
let result: bool = s.closure.call("hello world");
Upvotes: 3