The following Rust code is given:
struct Wrapper<T> {
data: Vec<T>, // more attributes...
}
trait DataWrapper<T> {
fn get_column(&self) -> &Vec<T>;
fn get_data(&self, row: usize) -> &T;
}
impl<T> DataWrapper<T> for Wrapper<T> {
fn get_column(&self) -> &Vec<T> {
&self.data
}
fn get_data(&self, row: usize) -> &T {
&self.data[row]
}
}
struct Inter<T> {
inter_value: Wrapper<T>,
}
trait GetInter {
fn get_count(&self) -> &str;
}
impl GetInter for Inter<i32> {
fn get_count(&self) -> &str {
"i32"
}
}
impl GetInter for Inter<f64> {
fn get_count(&self) -> &str {
"f64"
}
}
fn create_vector() -> Vec<Box<GetInter>> {
// Add some sample data
let x = Wrapper { data: vec![1, 2, 3] };
let y = Wrapper { data: vec![1.1, 2.2, 3.3] };
let mut vec: Vec<Box<GetInter>> = Vec::new();
let m = Inter { inter_value: x };
let m = Box::new(m);
let m = m as Box<GetInter>;
vec.push(m);
let n = Inter { inter_value: y };
let n = Box::new(n);
let n = n as Box<GetInter>;
vec.push(n);
vec
}
struct ColumnWrapper {
columns: Vec<Box<GetInter>>, // more attributes
}
fn create_column_wrapper() -> ColumnWrapper {
let result = create_vector();
ColumnWrapper { columns: result }
}
fn main() {
let result = create_column_wrapper();
for iter1 in result.columns {
println!("1: {}", iter1.get_count());
}
}
Wrapper<T>
stores a generic Vec
, in detail a data column from an column store. The corresponding implementation returns the Vec
or a specific element as reference.
The idea of the Inter<T>
and GetInter
traits is to hide the generic T
object, which comes from the Wrapper's Vec<T>
generic data type. The get_count()
method is only for test purposes.
create_vector()
creates two new Vec
s with some sample data. The result is cast to GetInter
, wrapped into a Box
and stored in a Vec<Box<GetInter>>
. Finally the caller will create a new ColumnWrapper
element. Now a generic data representation is given.
After compiling and running the correct result is given:
i32
f64
Now the real problem starts. I try to access the original data, which are stored in Wrapper<T>
.
My first idea was to use the dynamic dispatching feature from Rust. It should detect the real data type during runtime.
The main()
function is modified:
fn main() {
let result = create_column_wrapper();
for iter1 in result.columns {
println!("1: {}", iter1.get_count());
for iter2 in dyn_dispatch(*iter1) {
println!("2: {}", iter2);
}
}
}
The corresponding and not tested dyn_dispatch()
function:
trait Foo<T> {
fn method(x: &Inter<T>) -> &Vec<T>;
}
impl<i32> Foo<i32> for Inter<i32> {
fn method(x: &Inter<i32>) -> &Vec<i32> {
&x.inter_value.data
}
}
impl<f64> Foo<f64> for Inter<f64> {
fn method(x: &Inter<f64>) -> &Vec<f64> {
&x.inter_value.data
}
}
fn dyn_dispatch<T>(x: &GetInter) -> &Vec<T> {
Foo::method(&x as &Inter<T>)
}
The compilation fails and an error is thrown:
85:2 error: conflicting implementations of trait
Foo<_>
for typeInter<_>
: [E0119]
Any idea how to fix the compilation error or another and more easy idea to hide and access the generic T
object?
There are a couple of problems here.
The first error:
error: conflicting implementations of trait Foo<> for type Inter<>: [E0119]
actually refers to these:
impl<i32> Foo<i32> for Inter<i32> { ... }
impl<f64> Foo<f64> for Inter<f64> { ... }
Since i32
and f64
are parameters, those are both equivalent to:
impl<T> Foo<T> for Inter<T> { ... }
That is, the implementation of Foo<T>
for Inter<T>
for any T hence the conflicting implementations. The fix is to write them as:
impl Foo<i32> for Inter<i32> { ... }
The next problem is that you're not actually doing dynamic dispatch. Your dyn_dispatch
function would have to have T
specified or inferred at compile time; it can't return a different type each time; similarly you can't just downcast from GetInter
to Inter<T>
like that. You need to do it in the same way as you've done GetInter::get_count
.