Rust “的适当所有权”;“缓存代理”;锈迹斑斑?

Rust “的适当所有权”;“缓存代理”;锈迹斑斑?,rust,traits,ownership,Rust,Traits,Ownership,我想使用工厂从字符串构建一个对象,并具有多个impl:1)实际构建和2)缓存(存储在HashMap中的内存中)。问题是,在案例1中,它必须传递所有权,而在案例2中,HashMap拥有该值,并且只能返回一个引用 use std::collections::HashMap; // product interface pub trait TProduct { fn get_title(&self) -> &String; } // and concrete impl

我想使用
工厂
字符串
构建一个对象,并具有多个impl:1)实际构建和2)缓存(存储在
HashMap
中的内存中)。问题是,在案例1中,它必须传递所有权,而在案例2中,HashMap拥有该值,并且只能返回一个引用


use std::collections::HashMap;

// product interface
pub trait TProduct {
    fn get_title(&self) -> &String;
}

// and concrete impls
pub struct ConcreteProduct1 {
}

impl TProduct for ConcreteProduct1 {
// ...
}

pub struct ConcreteProduct2 {
}

impl TProduct for ConcreteProduct2 {
// ...
}

// factory interface
pub trait TProductFactory {
    fn product_from_text(&mut self, text: String) -> Box<dyn TProduct>;
    // QUESTION: should it be Box (required for ProductFactory) or &Box (required for ProductCachingProxy)?
}

// actual building factory
pub struct ProductFactory {
}

impl TProductFactory for ProductFactory {
    fn product_from_text(&mut self, text: String) -> Box<dyn TProduct> {
    //...
    // depending on some conditions 
    Box::new(ConcreteProduct1::from_text(text)); // has to pass the ownership
    // or
    Box::new(ConcreteProduct2::from_text(text)); // has to pass the ownership
    //...
    }
}

// caching proxy
trait TProductCache {
    fn put(&mut self, text: &String, product: Box<dyn TProduct>);
    fn get(&self, text: &String) -> Option<&Box<dyn TProduct>>;
    fn clear(&mut self);
}

struct InMemoryProductCache {
    map: HashMap<String, Box<dyn TProduct>>
}

impl InMemoryProductCache {
    fn new() -> Self {
        return InMemoryProductCache {
            map: HashMap::new()
        }
    }
}

impl TProductCache for InMemoryProductCache {
    fn put(&mut self, text: &String, product: Box<dyn TProduct>) {
        self.map.insert(text.to_string(), product);
    }

    fn get(&self, text: &String) -> Option<&Box<dyn TProduct>> {
        return match self.map.get(text) {
            Some(boxed_product) => Some(boxed_product), // have to pass a reference to let it still own the value
            None => None
        }
    }

    fn clear(&mut self) {
        self.map.clear();
    }
}

struct ProductCachingProxy {
    product_factory: Box<dyn TProductFactory>,
    cache: Box<dyn TProductCache>
}

impl ProductCachingProxy {
    fn new_for_factory(product_factory: Box<dyn TProductFactory>, cache: Box<dyn TProductCache>) -> Self {
        return ProductCachingProxy {
            product_factory,
            cache
        }
    }
}

impl TProductFactory for ProductCachingProxy {
    fn product_from_text(&mut self, text: String) -> &Box<dyn TProduct> { // can't pass ownership
        let boxed_product = match self.cache.get(&text) {
            Some(found_boxed_product) => found_boxed_product,
            _ => {
                // delegate creation to wrapped TProductFactory impl (`product_factory`)
                let boxed_product = self.product_factory.product_from_text(text.clone());
                // ... and put to the cache
                self.cache.put(&text, boxed_product);
                &boxed_product
            }
        };
        return boxed_product;
    }
}


使用std::collections::HashMap;
//产品界面
公共产品{
fn获取标题(&self)->&String;
}
//和混凝土
发布结构ConcreteProduct1{
}
针对ConcreteProduct1的impl TProduct{
// ...
}
发布结构ConcreteProduct2{
}
针对ConcreteProduct2的impl TProduct{
// ...
}
//工厂接口
酒吧生产厂{
fn product_from_text(&mut self,text:String)->Box;
//问题:应该是Box(ProductFactory需要)还是&Box(ProductCachingProxy需要)?
}
//实际建筑工厂
pub结构产品工厂{
}
为ProductFactory导入ProductFactory{
fn product\u from\u text(&mut self,text:String)->Box{
//...
//取决于某些条件
Box::new(ConcreteProduct1::from_text(text));//必须传递所有权
//或
Box::new(ConcreteProduct2::from_text(text));//必须传递所有权
//...
}
}
//缓存代理
特征产品缓存{
fn put(&mut self,文本:&String,产品:框);
fn get(&self,text:&String)->选项;
fn清除(&mut self);
}
结构InMemoryProductCache{
映射:HashMap
}
impl InMemoryProductCache{
fn new()->Self{
返回内存产品缓存{
map:HashMap::new()
}
}
}
InMemoryProductCache的impl TProductCache{
fn put(&mut self,文本:&String,产品:框){
self.map.insert(text.to_string(),product);
}
fn get(&self,text:&String)->选项{
返回匹配self.map.get(文本){
Some(boxed_product)=>Some(boxed_product),//必须传递一个引用以使其仍然拥有该值
无=>无
}
}
fn清除(&M自我){
self.map.clear();
}
}
结构ProductCachingProxy{
产品出厂:包装箱,
缓存:框
}
impl ProductCachingProxy{
fn新工厂(产品工厂:盒子,缓存:盒子)->Self{
退货产品CachingProxy{
产品制造厂,
隐藏物
}
}
}
ProductCachingProxy的impl TProductFactory{
fn product_from_text(&mut self,text:String)->&Box{//无法传递所有权
让boxed_product=匹配self.cache.get(&text){
一些(发现的盒装产品)=>发现的盒装产品,
_ => {
//将创建委托给包装的TProductFactory impl(`product\u factory`)
让boxed_product=self.product_factory.product_from_text(text.clone());
//…并放入缓存
self.cache.put(文本和盒装产品);
&盒装产品
}
};
退回盒装产品;
}
}
//问题:从
TProductFactory.fn product\u from_text(&mut self,text:String)->框返回的是
Box
(ProductFactory需要)还是
&Box
(ProductCachingProxy需要)


如果缓存代理返回
,如何从引用创建它而不复制/克隆(
TProductCache.get(…)
)?

替换为
Rc
(或者
Arc
,如果使用线程)。它提供共享所有权,并为您的两个案例提供单一签名。另一种选择是使用
Cow
,这是一个拥有和借用状态的枚举。

在性能方面,什么是首选(Rc vs Cow)?@4ntoine Cow意味着在使用它时只需检查一下,Rc维护参考计数器。更重要的区别是,Cow在任何地方都需要合适的寿命,而使用Rc时,你可以忘记它们。