Pro Poop
Pro Poop

Reputation: 456

How do I approach this trait object problem?

I have code similar to the one below (playground):

trait SomeTrait {
    fn some_fn(&self) -> i32;
}

#[derive(Debug, Clone, Eq, PartialEq)]
enum Foo {
    Bar,
    Baz(Box<dyn SomeTrait>),
}

fn main() {
    // Do something with Foo
}

I have a trait object being held in Foo::Baz and I want whatever to be in there to have Debug, Clone, and Eq derived. The above code won't compile and you'll get an error saying that the trait object doesn't implement the derived traits. I get why it doesn't compile. But I want to know how I can solve this problem. In my actual project, all the derived traits are necessary so simply removing them isn't an option. I thought about using super traits but when you try to write something like:

trait SomeTrait: DynClone + std::fmt::Debug + Eq + PartialEq {
    fn some_fn(&self) -> i32;
}

This would require the struct that SomeTrait is being implemented for to have already derived all of the required traits so that it can be used in Foo. Unfortunately now I get an error saying that the trait cannot be made into an object, and I don't understand what it means by that. Can anybody help me figure out how to tackle this problem?

Upvotes: 1

Views: 270

Answers (1)

Nikolay Zakirov
Nikolay Zakirov

Reputation: 1584

The error means that not every trait can be made into a trait object. Here is more detailed explanation. You can not use Self in generic parameters of such traits while all Clone, Eq and PartialEq do use Self. When using dyn (dynamic dispatch) there isn't enough information to know what Self is and therefore what type of reference the methods of Clone, Eq or PartialEq can accept(explained here and here).

Why don't you go with static dispatch instead of dynamic dispath? Then everything works and you have improved performance at runtime

use std::fmt::Debug;

trait SomeTrait{

    fn some_fn(&self) -> i32;
}

#[derive(Debug, Clone, Eq, PartialEq)]
enum Foo<T:SomeTrait> {
    Bar,
    Baz(T),
}

fn main() {
    // Do something with Foo
}

Upvotes: 4

Related Questions