Home > Blockchain >  Construct an array of objects in Rust
Construct an array of objects in Rust

Time:05-09

This is my very first Rust program that actually has a purpose and I'm still lost with the syntax. So I have trait objects like these:

trait HC<'a> {
    fn info(&self) -> TestInfo<'static>;
    fn test(&self) -> HCResult<'a>;
}

#[allow(non_camel_case_types)]
struct Test_NTP;
impl<'a> HC<'a> for Test_NTP {
    fn info(&self) -> TestInfo<'static> {
        TestInfo { ... }
    }

    fn test(&self) -> HCResult<'a> {
        ...
    }
}

#[allow(non_camel_case_types)]
struct Test_Last;
impl<'a> HC<'a> for Test_Last {
    fn info(&self) -> TestInfo<'static> {
        TestInfo { ... }
    }

    fn test(&self) -> HCResult<'a> {
        ...
    }
}

I want to construct an array of these objects those define the HC trait, tupled with an ID, so I can iterate through them and call their test() functions.

const HC_TESTS: [(i16, &dyn HC)] = [
    (1, &Test_NTP),
    (2, &Test_Last)
];

I tried several variations, but I always get a "doesn't have a size known at compile-time" error. I thought putting the objects in Boxes would solve the problem, but I get the same error:

error[E0277]: the size for values of type `[(i16, Box<&'static (dyn HC<'static>   'static)>)]` cannot be known at compilation time
   --> src/hc.rs:125:17
    |
125 | const HC_TESTS: [(i16, Box<&dyn HC>)] = [
    |                 ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[(i16, Box<&'static (dyn HC<'static>   'static)>)]`

The structs don't have any fields, the only reason I use them is to bound the info() and test() functions together, and I don't even use &self, they're only needed to dispatch virtual methods. What am I doing wrong?

CodePudding user response:

Your syntax is off just slightly. The error

the trait `Sized` is not implemented for `[(i16, Box<&'static (dyn HC<'static> 'static)>)]

refers to the most outer [...], which is a slice.

In

const HC_TESTS: [(i16, Box<&dyn HC>)] =

you explicitly set the type of HC_TESTS to be a slice, not an array. A slice is always unsized, so the compiler complains. What you want is simply

const HC_TESTS: [(i16, Box<&dyn HC>); 2] =

which sets the type of HC_TESTS to be an array of exactly two elements.

Notice that the other answers and comments here ("works for me") use this syntax as well.

CodePudding user response:

Your problem is that you cannot use & (you actually can, the problem is that you didn't actually set the array length [(i16, Box<dyn HC>); 2]).

Also you could have use Box. But since Box::new is not const, you would need to wrap it in some other lazy wrapper, std::lazy::Lazy is not stable jet but would work:

const HC_TESTS: Lazy<[(i16, Box<dyn HC>); 2]> = Lazy::new(|| [
    (1, Box::new(Test_NTP)),
    (2, Box::new(Test_Last))
]);

Playground

Meanwhile you can use once_cell Lazy, which works the same.

Another option is to wrap all of them in a enum, so you can construct them, and impl the trait for that enum so you can use it later:

enum Tests {
    NTP(Test_NTP),
    Last(Test_Last)
}

impl<'a> HC<'a> for Tests {
    fn info(&self) -> TestInfo<'static> {
        match self {
            Self::NTP(e) => e.info(),
            Self::Last(e) => e.info()
        }
    }

    fn test(&self) -> HCResult<'a> {
        match self {
            Self::NTP(e) => e.test(),
            Self::Last(e) => e.test()
        }
    }
}


const HC_TESTS: [(i16, Tests); 2] = [
    (1, Tests::NTP(Test_NTP)),
    (2, Tests::Last(Test_Last))
];

Playground

  • Related