Your enum doesn't represent what you think it does, as you've written it. Currently, it's just two variants that each contain no data. You want something like this:
Come up with your own names though, you can even call the variants the same as the types they contain if you want. I only changed it to show that the name is independent.
When using traits and generics, you can only access things that are defined on the trait. If you want to access fields, you must provide a method on the trait for doing so.
But why do you have two distinct types with identical layout in the first place? That, not Rust's trait system, is what seems to be the source of the code smell.
Oh! My real program has more fields for each struct.
I was trying to figure out how to pass the two types into a common function without using an enum. As such, was suggested using generics and traits.
Definitely not the best example..
Others can probably offer better advice than me, but maybe this context will be helpful.
Coming from an object-oriented background, it's easiest to think of traits like interfaces in Java / C# / etc. They expose behaviour (functions), but never the data members. It's just a defined way to interact with the object.
Traits are are great if your method needs to handle any number of different objects in the future, and you don't know what they all are right now.
Enums are great if you do know exactly what variants you want the function to handle, and the compiler will help you enforce this. And you do get to use the data inside them if you want to. These special enums are one of Rust's super powers, and you'll see them in plenty of functional languages. There is no equivalent in Java or C#.
You can also add a getter like fn id(&self) -> u32; to the trait and use that in other trait methods, or in some cases a constant like const ID: u32; might work, though probably not here.
But yes, there's no way to directly access fields of the implementing struct in default implementations. Making it possible to have fields in traits has been suggested before (see for example https://github.com/nikomatsakis/fields-in-traits-rfc/blob/master/0000-fields-in-traits.md) but I don't think that's something that's being actively worked on right now.
When I'm talking about the method handling different objects in the future, I'm talking about a method that takes a MyPersonalTrait as input. Hopefully this makes sense -- it's the one called use_trait in this example:
trait MyPersonalTrait{
fn increment_id(&mut self);
}
struct Thing1 {
id: i32
}
struct Thing2 {
some_other_id: i32
}
// this has to be implemented for each struct that
// implements the trait
impl MyPersonalTrait for Thing1 {
fn increment_id(&mut self) {
self.id += 1;
}
}
impl MyPersonalTrait for Thing2 {
fn increment_id(&mut self) {
self.some_other_id += 1;
}
}
// method using the trait - defined once, and will accept any MyPersonalTrait
fn use_trait<T: MyPersonalTrait>(thing: &mut T) {
thing.increment_id()
}
fn main() {
let mut t = Thing1 {
id: 12
};
let mut t2 = Thing2 {
some_other_id: 33
};
use_trait(&mut t);
println!("{}", t.id);
use_trait(&mut t2);
println!("{}", t2.some_other_id);
}