隐藏和接收通用T对象

时间:2016-07-22 12:45:50

标签: generics rust dynamic-dispatch

给出以下Rust代码:

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>存储通用Vec,详细列出了列商店中的数据列。相应的实现返回Vec或特定元素作为参考。

Inter<T>GetInter特征的想法是隐藏通用T对象,该对象来自Wrapper的Vec<T>通用数据类型。 get_count()方法仅用于测试目的。

create_vector()创建两个带有一些示例数据的新Vec。结果转换为GetInter,包含在Box中并存储在Vec<Box<GetInter>>中。最后,调用者将创建一个新的ColumnWrapper元素。现在给出了通用数据表示。

编译并运行后,会给出正确的结果:

i32 
f64

现在真正的问题开始了。我尝试访问存储在Wrapper<T>中的原始数据。

我的第一个想法是使用Rust的动态调度功能。它应该在运行时检测实际数据类型。

main()功能已修改:

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

相应且未经测试的dyn_dispatch()函数:

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>)
}

编译失败并抛出错误:

  

85:2错误:类型Foo<_>的特征Inter<_>实施冲突:[E0119]

任何想法如何修复编译错误或其他更多简单的想法来隐藏和访问通用T对象?

1 个答案:

答案 0 :(得分:4)

这里有几个问题。

第一个错误:

  

错误:trait Foo&lt; &gt;的冲突实现对于Inter&lt; &gt;类型:   [E0119]

实际上是指这些:

impl<i32> Foo<i32> for Inter<i32> { ... }
impl<f64> Foo<f64> for Inter<f64> { ... }

由于i32f64是参数,因此它们都等同于:

impl<T> Foo<T> for Inter<T> { ... }

也就是说,Foo<T> 为任何T 实施Inter<T>因此冲突的实现。解决方法是将它们写为:

impl Foo<i32> for Inter<i32> { ... }

下一个问题是你实际上并没有进行动态调度。您的dyn_dispatch函数必须在编译时指定或推断T;它每次都不能返回不同的类型;同样,你不能只是从GetInter转发到Inter<T>。您需要以与完成GetInter::get_count相同的方式完成此操作。