作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前使用以下模式在容器中存储多个不同的用户定义类型。
use std::any::{Any, TypeId};
use std::collections::HashMap;
#[derive(Default)]
struct Container {
inner: HashMap<TypeId, Box<Any>>,
}
impl Container {
pub fn insert<T: Any>(&mut self, data: T) {
self.inner.insert(TypeId::of::<T>(), Box::new(data));
}
pub fn borrow<T: Any>(&self) -> Option<&T> {
self.inner.get(&TypeId::of::<T>())
.and_then(|a| a.downcast_ref::<T>())
}
}
现在,我想不再使用盒装特征对象,而是使用枚举代替它们(类型参数 G
),但要保持相同的面向外的 API。这里的目标是通过使用一个枚举来绕过虚拟化,该枚举封装了每个已知的用户提供的类型T
:
use std::any::{Any, TypeId};
use std::collections::HashMap;
struct Container<G> {
inner: HashMap<TypeId, G>,
}
impl<G> Default for Container<G> {
fn default() -> Self {
Container {
inner: Default::default(),
}
}
}
impl<G> Container<G> {
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> {
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)
}
}
#[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));
}
}
我将如何着手实现 borrow
方法?非常感谢您的帮助!
最佳答案
我可以使用 Any
上的 downcast_ref
方法从实现 GroupTrait
的枚举向下转型:
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())
}
}
#[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));
}
}
关于rust - 如何在保持相同 API 的同时用枚举替换 Any 的盒装特征对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49457323/
我是一名优秀的程序员,十分优秀!