我有一个结构体,看起来像这样:
pub struct MyStruct<F>
where
F: Fn(usize) -> f64,
{
field: usize,
mapper: F,
// fields omitted
}
我如何实现这个结构的Clone
?
let mapper = |x| (mystruct.mapper)(x);
但这导致mapper
与mystruct.mapper
具有不同的类型。
从Rust 1.26.0开始,如果所有捕获的变量都实现了Copy
和Clone
,闭包将同时实现:
#[derive(Clone)]
pub struct MyStruct<F>
where
F: Fn(usize) -> f64,
{
field: usize,
mapper: F,
}
fn main() {
let f = MyStruct {
field: 34,
mapper: |x| x as f64,
};
let g = f.clone();
println!("{}", (g.mapper)(3));
}
你不能Clone
闭包。唯一能够实现闭包Clone
的是编译器…它不。所以,你有点被卡住了。
有一个方法可以解决这个问题:如果你有一个闭包,其中没有捕获的变量,你可以通过unsafe
代码强制复制。也就是说,对于点,更简单的方法是接受fn(usize) -> f64
而不是,因为它们没有捕获环境(任何零大小的闭包都可以重写为函数),并且是Copy
.
您可以使用Rc
(或Arc
!)来获得相同不可克隆值的多个句柄。可以很好地与Fn
(可通过共享引用调用)闭包一起使用。
pub struct MyStruct<F> where F: Fn(usize) -> f64 {
field: usize,
mapper: Rc<F>,
// fields omitted
}
impl<F> Clone for MyStruct<F>
where F: Fn(usize) -> f64,
{
fn clone(&self) -> Self {
MyStruct {
field: self.field,
mapper: self.mapper.clone(),
...
}
}
}
请记住,#[derive(Clone)]
是克隆的一个非常有用的配方,但它的配方并不总是做正确的事情;
你可以使用trait对象来为你的struct实现Сlone
:
use std::rc::Rc;
#[derive(Clone)]
pub struct MyStructRef<'f> {
field: usize,
mapper: &'f Fn(usize) -> f64,
}
#[derive(Clone)]
pub struct MyStructRc {
field: usize,
mapper: Rc<Fn(usize) -> f64>,
}
fn main() {
//ref
let closure = |x| x as f64;
let f = MyStructRef { field: 34, mapper: &closure };
let g = f.clone();
println!("{}", (f.mapper)(3));
println!("{}", (g.mapper)(3));
//Rc
let rcf = MyStructRc { field: 34, mapper: Rc::new(|x| x as f64 * 2.0) };
let rcg = rcf.clone();
println!("{}", (rcf.mapper)(3));
println!("{}", (rcg.mapper)(3));
}