反射需要类型注释

时间:2018-03-21 08:30:24

标签: reflection rust

我正在尝试隐藏impl Foo的类型信息并存储此信息以供日后使用。这甚至可能吗?

#![feature(universal_impl_trait)]

use std::any::Any;
use std::marker::PhantomData;

trait Foo {
    type Item;
    fn get(&self) -> Self::Item;
}

#[derive(Clone, Debug)]
struct Bar<T: Clone>(T);
impl<T: Clone> Bar<T> {
    fn new(t: T) -> Self {
        Bar(t)
    }
}
impl<T: 'static + Clone> Foo for Bar<T> {
    type Item = T;
    fn get(&self) -> Self::Item {
        self.0.clone()
    }
}

#[derive(Clone, Debug)]
struct Baz<T: Clone, F: Clone>(T, F);
impl<T: Clone, F: Clone> Baz<T, F> {
    fn new(t: T, f: F) -> Self {
        Baz(t, f)
    }
}
impl<T: 'static + Clone, F: 'static + Clone> Foo for Baz<T, F> {
    type Item = (T, F);
    fn get(&self) -> Self::Item {
        (self.0.clone(), self.1.clone())
    }
}

trait Get {
    type Item;
    fn idx(&self) -> usize;
}

struct GetBar<T> {
    id: usize,
    _t: PhantomData<T>,
}
impl<T> Get for GetBar<T> {
    type Item = T;
    fn idx(&self) -> usize {
        self.id
    }
}
impl<T> GetBar<T> {
    fn new(id: usize) -> Self {
        Self {
            id,
            _t: PhantomData,
        }
    }
}

struct GetBaz<T, F> {
    id: usize,
    _t: PhantomData<T>,
    _f: PhantomData<F>,
}
impl<T, F> Get for GetBaz<T, F> {
    type Item = T;
    fn idx(&self) -> usize {
        self.id
    }
}
impl<T, F> GetBaz<T, F> {
    fn new(id: usize) -> Self {
        GetBaz {
            id,
            _t: PhantomData,
            _f: PhantomData,
        }
    }
}

struct Qux {
    v: Vec<Box<Any>>,
}
impl Qux {
    fn new() -> Self {
        Qux { v: vec![] }
    }

    fn add_bar<T: 'static + Clone>(&mut self, a: T) -> GetBar<T> {
        self.v.push(Box::new(Bar::new(a)) as Box<Any>);
        GetBar::new(self.v.len())
    }

    fn add_baz<T: 'static + Clone, F: 'static + Clone>(&mut self, a: T, b: F) -> GetBaz<T, F> {
        self.v.push(Box::new(Baz::new(a, b)) as Box<Any>);
        GetBaz::new(self.v.len())
    }

    fn get<T: 'static + Clone, F: 'static + Clone>(&self, val: &'static impl Get) -> Option<T> {
        let node = &self.v[val.idx()];
        if let Some(foo) = node.downcast_ref::<Bar<T>>() {
            Some(foo.get())
        } else if let Some(foo) = node.downcast_ref::<Baz<T, F>>() {
            Some(foo.get().0)
        } else {
            None
        }
    }
}

fn main() {
    let mut qux = Qux::new();

    let a = qux.add_bar(1_i32);
    let b = qux.add_bar("1");
    let c = qux.add_baz(Bar::new('A'), Bar::new('B'));

    assert_eq!(qux.get(&a).unwrap(), 1);
    assert_eq!(qux.get(&b).unwrap(), "i");
    assert_eq!(qux.get(&c).unwrap(), Bar::new('A'));
}
error[E0283]: type annotations required: cannot resolve `_: std::clone::Clone`
   --> src/main.rs:121:20
    |
121 |     assert_eq!(qux.get(&a).unwrap(), 1);
    |                    ^^^

很抱歉这个长期的例子,但这是我能做的最好的。

我试图将Rust静态类型系统与动态调度的特征对象进行协调。但是,在很多情况下,我无法提供类型注释。实现这一目标的最佳方法是什么?如何动态地向特征对象系统提供类型信息?

qux.add_baz(GetBar::<&str>::new(1), GetBaz::<i32, i32>::new(3));如何使用该类型信息以递归方式从qux获取?

抱歉这个人为的例子; real code is available on GitHub

0 个答案:

没有答案