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))
]);
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))
];