我正在尝试隐藏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。