如果我想要一个不可复制的类型擦除(动态类型)可调用,那就是
Box<dyn Fn(i32) -> ()>
Run Code Online (Sandbox Code Playgroud)
如果我想要一个引用计数类型擦除的可调用对象,那就是(取决于我是否需要线程安全)
Rc<dyn Fn(i32) -> ()>
Arc<dyn Fn(i32) -> ()>
Run Code Online (Sandbox Code Playgroud)
但在这里,这些副本都引用相同的底层内存——它们并不不同。
如果我想要不同的可调用对象,我该怎么做?当Implements时Box<T>已经实现,但未实现,因此不适用于此处。做类似的事情:CloneTCloneFnClone
Box<dyn Fn(i32) -> () + Clone>
Run Code Online (Sandbox Code Playgroud)
失败并显示:
error[E0225]: only auto traits can be used as additional traits in a trait object
--> src/main.rs:7:35
|
7 | fn foo(f: Box<dyn Fn(i32) -> () + Clone>) {
| ------------- ^^^^^ additional non-auto trait
| |
| first non-auto trait
|
= help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Fn<(i32,)> + Clone {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
Run Code Online (Sandbox Code Playgroud)
由于 的拼写,错误中的建议不起作用Fn,但是:
trait CopyableFn: Fn(i32) -> () + Clone {}
Box<dyn CopyableFn>
Run Code Online (Sandbox Code Playgroud)
其本身也不起作用,因为:
error[E0038]: the trait `CopyableFn` cannot be made into an object
--> src/main.rs:7:11
|
5 | trait CopyableFn: Fn(i32) -> () + Clone {}
| ---------- ----- ...because it requires `Self: Sized`
| |
| this trait cannot be made into an object...
6 |
7 | fn foo(f: Box<dyn CopyableFn>) {
| ^^^^^^^^^^^^^^^^^^^ the trait `CopyableFn` cannot be made into an object
Run Code Online (Sandbox Code Playgroud)
有没有一种方法可以创建可克隆的类型对象,Fn以便副本是不同的?
实现一个将其克隆到盒子中的方法,而不是CloneableFn成为 的超级特征:Cloneclone_box
trait CloneableFn: Fn(i32) -> () {
fn clone_box<'a>(&self) -> Box<dyn 'a + CloneableFn>
where
Self: 'a;
}
Run Code Online (Sandbox Code Playgroud)
由于像这样的未调整大小的类型dyn CloneableFn无法克隆(Clone需要Sized),因此没有理由Clone在这里将其作为超级特征。然而,作为Fn(i32) -> ()超级特征允许函数正常调用。
然后可以为所有同时实现和 的CloneableFn类型实现:Fn(i32) -> ()Clone
impl<F> CloneableFn for F
where
F: Fn(i32) -> () + Clone,
{
fn clone_box<'a>(&self) -> Box<dyn 'a + CloneableFn>
where
Self: 'a,
{
Box::new(self.clone())
}
}
Run Code Online (Sandbox Code Playgroud)
最后,Box<dyn CloneableFn>不会自动实现,Clone因为dyn CloneableFn不会,所以我们可以自己实现:
impl<'a> Clone for Box<dyn 'a + CloneableFn> {
fn clone(&self) -> Self {
(**self).clone_box()
}
}
Run Code Online (Sandbox Code Playgroud)
有了这个,您现在可以克隆Box<dyn CloneableFn> 并将其作为常规函数调用:
// let closure borrow some shared state
use std::sync::atomic::{AtomicI32, Ordering};
let x = AtomicI32::new(0);
let f = |n| {
println!("x = {}", x.fetch_add(n, Ordering::Relaxed));
};
let f: Box<dyn CloneableFn> = Box::new(f);
let g = f.clone();
f(3);
g(5);
f(7);
Run Code Online (Sandbox Code Playgroud)
这与如何克隆存储装箱特征对象的结构有关?,但在这种情况下,目标特征 ( Animal) 可以更改为具有超级特征,而在这种情况下这是不可能的(因为目标特征是Fn(i32) -> ())。在某种程度上,这是相反的方法:添加目标是超级特征的特征,而不是向目标添加超级特征。
| 归档时间: |
|
| 查看次数: |
1194 次 |
| 最近记录: |