我尝试将多个闭包传递给一个结构,并将它们存储为盒装的特征对象。这些闭包被包装在线程安全(Send,Sync)和可克隆(Clone)结构中。
use std::thread;
// make trait alias
trait SafeFnMut: FnMut() + Send + Sync {}
impl<F> SafeFnMut for F where F: FnMut() + Send + Sync {}
#[derive(Clone, Debug)]
struct WithCall<F> where F: Sized {
fp: Box<F>,
}
impl<F> WithCall<F> where F: SafeFnMut {
// boxing the closure here
pub fn new(fp: F) -> Self {
WithCall { fp: Box::new(fp) }
}
pub fn run(&mut self) {
(self.fp)()
}
}
struct HasWithCall<T> where T: SafeFnMut {
pub first_fn: Option<Box<WithCall<T>>>,
pub second_fn: Option<Box<WithCall<T>>>,
}
fn main() {
let mut first_fn = WithCall::new(|| {
println!("Called!")
});
let mut second_fn = WithCall::new(|| {
println!("Called other!")
});
let has_with_call = HasWithCall {
first_fn: Some(Box::new(first_fn.clone())),
second_fn: Some(Box::new(second_fn.clone()))
};
println!("{:?}", first_fn.run());
let mut first_fn_a = first_fn.clone();
let mut first_fn_b = first_fn;
let a = thread::spawn(move || {
println!("In remote thread: {:?}", first_fn_a.run());
});
let b = thread::spawn(move || {
println!("In remote thread: {:?}", first_fn_b.run());
});
a.join().expect("Thread A panicked");
b.join().expect("Thread B panicked");
}这段代码给出了以下错误:
error[E0308]: mismatched types --> src/main.rs:39:34
second_fn: Some(Box::new(second_fn.clone()))
^^^^^^^^^^^^^^^^^ expected closure, found a different closure
note: expected type `WithCall<[closure@src/main.rs:29:38: 31:6]>`
found type `WithCall<[closure@src/main.rs:33:39: 35:6]>`
note: no two closures, even if identical, have the same type
help: consider boxing your closure and/or using it as a trait object我为线程安全闭包引用了this question,为闭包类型错误引用了this question。
我看到还有其他选项,比如对特征对象或函数指针的引用。不过,我想像上面写的那样,使用盒装的特征对象来解决这个问题。
发布于 2019-10-04 03:40:17
之所以会出现Expected closure, found a different closure中的错误消息,是因为Vec<T>只能包含一个具体类型T的闭包。在您的例子中,添加第二个类型参数U看起来更容易,这样您就可以拥有两个不同类型的不同闭包:
struct HasWithCall<T, U>
where
T: SafeFnMut,
U: SafeFnMut,
{
pub first_fn: Option<Box<WithCall<T>>>,
pub second_fn: Option<Box<WithCall<U>>>,
}顺便说一句,额外的Box对我来说似乎没有必要;使用Option<WithCall<T>>可能就足够了,因为WithCall中有一个Box。
https://stackoverflow.com/questions/58224969
复制相似问题