rust - 如何使用 remove 方法扩展基于枚举的多类型容器?

标签 rust

此问题基于 another recent question of mine 中给出的信息.我想扩展以下 Containerremove将存储数据的所有权返回给调用者的方法。随附的单元测试应解释其所需的行为。

在之前的案例中(参见引用问题),我会使用 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));
    }
}

最佳答案

正如您在评论中提到的,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())
}

Playground

我会选择 Into<Option<T>>TryInto<T>因为Into<Option<T>>结果 Option同时 TryInto<T>结果 Result<T, Self::Error>

关于rust - 如何使用 remove 方法扩展基于枚举的多类型容器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49491819/

相关文章:

algorithm - 具有奇怪行为的 Rust RSA 实现

rust - 如何将套接字作为参数传递给在线程中调用的函数?

arrays - 是否有一种正确的方法可以在引用一维中转换二维数组

enums - Rust 中的显式生命周期错误

rust - 我如何根据 Cargo 功能选择性地传递 rustc 标志?

rust - 我可以有条件地提供特征函数的默认实现吗?

rust - 在一个表达式中两次借用 self 有时会导致错误

recursion - 如何构建用于递归遍历文件树的迭代器?

rust - 为什么我不能在需要可变引用时将异步函数作为字段传递?

rust - 有没有办法命名 Rust doctest?