rust-lang-nursery / lazy-static.rs

A small macro for defining lazy evaluated static variables in Rust.
Apache License 2.0
1.9k stars 111 forks source link

Using dynamic dispatch with `lazy_static` #169

Open HarrisonMc555 opened 4 years ago

HarrisonMc555 commented 4 years ago

I'm not super experienced with dynamic dispatch, so there may be a better approach to solve this problem—feel free to point me in the right direction.

I want to have an enum translate to a lazy_static singleton. This is the classic example of something that wants to be const but requires allocation. However, I have two different types that I want the enum to translate to. To enable this, I wrapped the type in a Box<dyn Trait>. However, that doesn't appear to work with lazy_static.

Is there a way to resolve this situation? Here's an example of the kind of thing I'm trying to do:

lazy_static! {
    static ref ENUM_A_BOX: Box<dyn Trait> = Box::new(StructA {});
    static ref ENUM_B_BOX: Box<dyn Trait> = Box::new(StructB {});
    static ref ENUM_C_BOX: Box<dyn Trait> = Box::new(StructC {});
}

enum Enum {
    A,
    B,
    C,
}

impl Enum {
    pub fn to_lazy_box(&self) -> Box<dyn Trait> {
        match self {
            Enum::A => *ENUM_A_BOX,
            Enum::B => *ENUM_B_BOX,
            Enum::C => *ENUM_C_BOX,
        }
    }
}

trait Trait {}

struct StructA {}
struct StructB {}
struct StructC {}

impl Trait for StructA {}
impl Trait for StructB {}
impl Trait for StructC {}
LukasKalbertodt commented 4 years ago

The error you are getting is because all statics created with lazy_static have to be Send and Sync. If you change Box<dyn Trait + Send + Sync>, it works. (I had to change another unrelated problem, but nevermind.)

Apart from that: do you need to return Box<_> from to_lazy_box? Are you sure? If not, you could just make the statics have the type Box<StructA> (and B and C) and return a &dyn Trait from to_lazy_box.

And I do understand you correctly that this is a question rather than a feature request, right?