I encountered a scenario where I wanted to create an object of type Arc<Vec<T>> (where T implements the FadbModel trait, which contains some APIs for accessing data), and then convert it to Arc<dyn Any + 'static>. However, when processing the data, I found that I couldn't obtain the T type object, only knowing that the elements in the Vec implement the FadbModel trait.
Here, I hope to convert the type to Arc<Vec<FadbModel>> (or a similar type of object) so that I can access the data of the elements inside. It is now known that types like Vec<Box<T>> and Vec<&'a FadbModel> should be avoided as much as possible to minimize memory fragmentation and ensure that each element is properly cleaned up when the object is cleared.
And, objects of type Vec<> can know the size of their elements, as the total length/number of elements can be obtained. Therefore, I hope Rust supports such syntax so that I can handle this issue correctly:
pub trait FadbModel {
// some apis
}
pub struct TestTable {}
impl FadbModel for TestTable {}
// ...
let data: Arc<Vec<TestTable>> = Arc::new(vec![]);
let data2: for<T: FadbModel> Arc<Vec<T>> = data;
for item in data2.iter() {
// access FadbModel apis...
}
By the way, Does anyone know how the current Rust syntax can be utilized to help me solve this problem? very grateful
To me it seems the main question is: do you want a homogenous or a heterogenous collection?
In other words, should the same Vec be able to contain two different types (given that they implement FadbModel)?
If so, then you must have trait objects inside the Vec, including some indirection, or have a bounded set of types and use an enum.
Can you elaborate or provide a source on this? Indirection may require an allocation and does kill cache locality, but these seem to be a different set of drawbacks than those you are describing. (Also note that basically every garbage collected language does that, so unless your application is very specific or needs very high performance, this is unlikely to be a problem.)
It will never be possible to express what you want this way, not even with new language features, because “the set of all types implementing FadbModel” is often an infinite set, so this would require an infinite amount of monomorphic code. For example, very many traits can be, should be, and are implemented for pointer types:
impl<T> FadbModel for Box<T> where T: FadbModel {
// delegate to T...
}
Thus, Box<TestTable>, Box<Box<TestTable>>, etc. are all types that implement FadbModel, and there is an infinite set. There’s also the possibility that the specific T in use is a type that wasn’t known when this code was compiled, so there’s no way for it to have the required T-specific machine code available to it.
The way to get what you want is to, instead, define and implement a trait for the collection; something like:
Then you can have an Arc<dyn FadbList> and operate on it without involving Any1 and downcasting. You can’t use downcasting for this; you have to use a trait that provides the specific operations you want.
Yes, each such type would have a different vtable, in the general case and certainly in any case involving dereferencing.
But even if that wasn’t true, there’s no way that dyn Any could know that it should make that vtable available for downcasting to dyn FadbModel. You can’t make a data structure that lists all traits, for the same reason you can’t make code or a data structure that lists all implementations — it's an infinite set and an open set (can be extended by downstream crates).
I don't think so. I think that once we implement the trait, we can use its vtable
I don't need to know the actual type, I just need to know the type size and confirm that it implements the trait, so that I can pass the variable address to the virtual function in vtable
Sorry, my understanding was incorrect. Rust contains virtual tables through fat pointers, so it cannot directly obtain a reference to a trait object through a certain memory address. I have revised my initial idea