此问题基于another recent question of mine中提供的信息。我想用Container
方法扩展以下remove
,该方法将存储数据的所有权返回给调用者。随附的单元测试应解释其所需的行为。
在上一个案例中(参见引用的问题),我会在downcast
对象上使用Box<Any>
方法,但我不知道如何解决问题而是使用枚举。我很感激指点。
use std::any::{Any, TypeId};
use std::collections::HashMap;
trait GroupTrait {
fn borrow<T: Any>(&self) -> Option<&T>;
}
struct Container<G> {
inner: HashMap<TypeId, G>,
}
impl<G> Default for Container<G>
where
G: GroupTrait,
{
fn default() -> Self {
Container {
inner: Default::default(),
}
}
}
impl<G> Container<G>
where
G: GroupTrait,
{
pub fn insert<T: Any + Into<G>>(&mut self, data: T) {
self.inner.insert(TypeId::of::<T>(), data.into());
}
pub fn borrow<T: Any>(&self) -> Option<&T> {
self.inner.get(&TypeId::of::<T>()).and_then(|g| g.borrow())
}
pub fn remove<T: Any>(&mut self) -> Option<T> {
unimplemented!()
}
}
#[cfg(test)]
mod tests {
use super::*;
/// This should be an user-defined type that implements the Any trait.
#[derive(Debug, Clone, PartialEq)]
struct TypeA(u32);
/// This should be an user-defined type that implements the Any trait.
#[derive(Debug, Clone, PartialEq)]
struct TypeB(String);
/// This is the enum that should replace boxed `Any` trait objects. Users also need to supply
/// this enum. Maybe they'll need to implement additional traits to get `borrow` to work.
#[derive(Debug, PartialEq)]
enum Group {
A(TypeA),
B(TypeB),
}
impl From<TypeA> for Group {
fn from(value: TypeA) -> Self {
Group::A(value)
}
}
impl From<TypeB> for Group {
fn from(value: TypeB) -> Self {
Group::B(value)
}
}
impl GroupTrait for Group {
fn borrow<T: Any>(&self) -> Option<&T> {
use self::Group::*;
match *self {
A(ref i) => Any::downcast_ref(i),
B(ref i) => Any::downcast_ref(i),
}
}
}
#[test]
fn insert() {
let mut c: Container<Group> = Default::default();
let data = TypeA(100);
c.insert(data.clone());
assert_eq!(
c.inner.get(&TypeId::of::<TypeA>()),
Some(&Group::A(data.clone()))
);
}
#[test]
fn borrow() {
let mut c: Container<Group> = Default::default();
let data = TypeA(100);
c.insert(data.clone());
let borrowed = c.borrow::<TypeA>();
assert_eq!(borrowed, Some(&data));
}
#[test]
fn remove() {
let mut c: Container<Group> = Default::default();
let data = TypeA(100);
c.insert(data.clone());
assert_eq!(c.remove::<TypeA>(), Some(data));
}
}
答案 0 :(得分:1)
正如您在评论中提到的,TryFrom
是可能的。但是,我会选择Into<Option<T>>
:
pub fn remove<T: Any>(&mut self) -> Option<T>
where
G: Into<Option<T>>,
{
self.inner.remove(&TypeId::of::<T>()).and_then(|g| g.into())
}
我选择Into<Option<T>>
而非TryInto<T>
,因为Into<Option<T>>
会产生Option
而TryInto<T>
会产生Result<T, Self::Error>