Here's what I want to do:
struct Foo<T: Trait> {
inner: T,
}
struct Bar<'a> {
foo: &'a Foo<dyn Trait>, // This is pseudo code, I don't think Rust has this feature.
}
I want an instance of Bar
to hold a reference to a Foo
where the type parameter of Foo
is dynamic, ie over the lifetime of a single Bar
it may hold different instances of Foo
with different types for T
. Since Bar
only holds a reference, it would still be Sized
. As far as I can tell this is impossible right now. If this were possible, then I could do it multiple times in the same type, ie
struct Foo<T: Trait, U: Trait> {
a: T,
b: U,
}
struct Bar<'a> {
foo: &'a Foo<dyn Trait, dyn Trait>,
}
Now foo
needs to hold at least three pieces of information: a pointer, a pointer to a vtable for T, and a pointer to a vtable for U. This is unlike references to DSTs as they currently exist in the language, which hold two pieces of information: &[T]
holds a pointer and a length, and &dyn Trait
which holds a pointer and a pointer to a vtable. I think this could be feasible, but as far as I'm aware nothing like this exists in Rust at the moment. So, what's the closest thing to what I want to do?
Actually, on second thought, foo
in the above example could just hold one vtable pointer, and we could have a separate vtable for every combination of T
and U
. So maybe this is possible right now??
This is possible actually!
If you compile the first example you get this error:
error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
--> src/lib.rs:8:10
|
8 | foo: &'a Foo<dyn Trait>,
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Trait + 'static)`
note: required by a bound in `Foo`
--> src/lib.rs:3:12
|
3 | struct Foo<T: Trait> {
| ^ required by this bound in `Foo`
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> src/lib.rs:3:12
|
3 | struct Foo<T: Trait> {
| ^ this could be changed to `T: ?Sized`...
4 | inner: T,
| - ...if indirection were used here: `Box<T>`
It somewhat hints that you can relax the implicit Sized
bound by using ?Sized
, and doing so will make the Foo<dyn Trait>
declaration compile!
struct Foo<T: Trait + ?Sized> {
inner: T,
}
However, your intuition is correct that this cannot extend beyond a single dynamically-sized field. If you were to try the same trick on the second example, you'd get an error:
struct Foo<T: Trait + ?Sized, U: Trait + ?Sized> {
a: T,
b: U,
}
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> src/lib.rs:4:6
|
3 | struct Foo<T: Trait + ?Sized, U: Trait + ?Sized> {
| - this type parameter needs to be `std::marker::Sized`
4 | a: T,
| ^ doesn't have a size known at compile-time
|
= note: only the last field of a struct may have a dynamically sized type
= help: change the field's type to have a statically known size
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
3 - struct Foo<T: Trait + ?Sized, U: Trait + ?Sized> {
3 + struct Foo<T: Trait, U: Trait + ?Sized> {
|
help: borrowed types always have a statically known size
|
4 | a: &T,
| +
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
4 | a: Box<T>,
| ++++ +
Emphasis on the "only the last field of a struct may have a dynamically sized type" which gives an indication of how dynamically-sized types are implemented by the compiler.
Actually, on second thought,
foo
in the above example could just hold one vtable pointer, and we could have a separate vtable for every combination ofT
andU
. So maybe this is possible right now??
Unfortunately no, this is not supported.
Dynamically-sized types aren't particularly well supported and thus their current implementation is simplistic. For example, you can't actually construct a Foo<dyn Trait>
directly, you can only create one by first creating a Foo<T>
and coercing it into a Foo<dyn Trait>
. And of course, in that scenario Foo
itself becomes a DST and thus can only be used behind some kind of indirection (reference, Box
, Rc
, etc.).
See also:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.