If I want a non-copyable type-erased (dynamically-typed) callable, that's
Box<dyn Fn(i32) -> ()>
If I want a ref-counted type-erased callable, that's (depending on whether I need thread-safety or not)
Rc<dyn Fn(i32) -> ()>
Arc<dyn Fn(i32) -> ()>
But here, the copies all refer to the same underlying memory - they're not distinct.
If I want distinct callable objects, how can I do that? Box<T>
already implements Clone
when T
implements Clone
, but Fn
does not implement Clone
so that doesn't apply here. Doing something like:
Box<dyn Fn(i32) -> () + Clone>
fails with:
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>
The suggestion in the error doesn't work because of the spelling of Fn
, but this:
trait CopyableFn: Fn(i32) -> () + Clone {}
Box<dyn CopyableFn>
By itself also doesn't work because:
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
Is there a way of creating a type object for Fn
that is clonable such that the copies are distinct?