此问题在此处已有答案:
How to clone a struct storing a boxed trait object?(3个答案)
两年前关闭了。
如果我想要一个不可复制的类型-擦除(动态类型)可调用,那就是
Box<dyn Fn(i32) -> ()>
如果我想要一个引用计数类型擦除的可调用对象,那就是(取决于我是否需要线程安全)
Rc<dyn Fn(i32) -> ()>
Arc<dyn Fn(i32) -> ()>
但在这里,这些副本都指向同一个潜在的记忆--它们并不独特。
如果我想要 distinct 可调用对象,我该怎么做呢?Box<T>
已经实现了Clone
,而T
实现了Clone
,但是Fn
没有实现Clone
,所以这在这里不适用。
Box<dyn Fn(i32) -> () + Clone>
失败:
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>
错误中的建议不起作用,因为拼写为Fn
,但这:
trait CopyableFn: Fn(i32) -> () + Clone {}
Box<dyn CopyableFn>
它本身也不起作用,因为:
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
有没有一种方法可以为Fn
创建一个可克隆的类型对象,使副本是不同的?
1条答案
按热度按时间gj3fmq9x1#
与其让
CloneableFn
成为Clone
的supertrait,不如实现一个clone_box
方法,将其克隆到一个盒子中:由于像
dyn CloneableFn
这样的未调整大小的类型不能被克隆(Clone
需要Sized
),所以在这里没有理由将Clone
作为超trait。然而,将Fn(i32) -> ()
作为超trait允许正常调用函数。然后
CloneableFn
可以为所有同时实现Fn(i32) -> ()
和Clone
的类型实现:最后,
Box<dyn CloneableFn>
不会自动实现Clone
,因为dyn CloneableFn
不会,所以我们可以自己实现:有了这个,你现在可以克隆
Box<dyn CloneableFn>
* 并 * 将其作为常规函数调用:Here's a full playground example
这与How to clone a struct storing a boxed trait object?相关,但在这种情况下,目标trait(
Animal
)可以被更改为具有超trait,而在这种情况下,这是不可能的(因为目标trait是Fn(i32) -> ()
)。在某种程度上,这是相反的方法:添加所述目标是其超特征的特征,而不是将超特征添加到所述目标。