Hi Rust friends!
I have a (intermediate?) noob question! In Go, this would simply be an array of Interface types. But this is much more difficult in Rust.
I'm writing a niche kind of parser. I have a set of identical signature methods which I need implemented on a number of structural types, each with a different implementation.
trait MyTrait {
fn transition(&self, c: char) -> MatchResult; // Match Result type omitted as irrelevant.
fn show_debug(&self) -> String;
}
I also want to use Bodil's im
crate, particularly her OrdSet type. Now, there's a type bound on the OrdSet
's element that they must implement Clone
. Since Clone
is not object-safe, does this fundamentally mean that you cannot store trait objects in this data structure no matter what you do? Only algebraic and structural types? I can't even have a structural type
Is there really no way for me to wrap MyTrait
so I can store it in an OrdSet
? My understanding is that Clone
is incompatible with trait objects because Clone requires that the implementation not be object-safe; that is, any trait object instance might have a different size from any other instance, so rustc can't determine how much memory on the stack is need to store return the result of a call to .clone()
.
However in my case, each implementation of MyTrait
is sized (they are all enums or structural types by definition).
I tried the following:
- First, I had
MyTrait
inherit fromClone
trait MyTrait: Clone {
fn transition(&self, c: char) -> MatchResult; // Match Result type omitted as irrelevant.
fn show_debug(&self) -> String;
}
This fails because
the trait `MyTrait` cannot be made into an object
= note: the trait cannot require that `Self : Sized`
- Next, I added the
Sized
bound
trait MyTrait: Clone + Sized {
fn transition(&self, c: char) -> MatchResult; // Match Result type omitted as irrelevant.
fn show_debug(&self) -> String;
}
This fails for the same reason with the same error message. It is unclear to me why this fails, since I've now explicitly said that the trait can require that Self: Sized
- Finally, I tried to add a trait bound to my
OrdSet
type.
struct Wrapper {
my_set: OrdSet<MyTrait + Clone>,
}
This produces the error
error[E0225]: only auto traits can be used as additional traits in a trait object
--> src/main.rs:4:24
|
4 | array: Vec<MyTrait+Clone>,
| ^^^^^ non-auto additional trait
which seems to indicate that these kinds of ad-hoc bounds aren't permitted on trait object instances.
I know that I can wrap all implementations of MyTrait
in an enum to make them both sized and clone-able, but I want upstream modules to be able to pass in their own implementation of MyTrait
.
Thank you very much for your feedback and patience.