Rust 中 "caching proxy" 的正确所有权?

The proper ownership for "caching proxy" in Rust?

我想使用 FactoryString 构建对象并有多个实现:1) 实际构建和 2) 缓存(存储在内存中 HashMap).问题是,如果 #1 它必须传递所有权,如果 #2 HashMap 拥有该值并且引用只能 returned。


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;
    }
}

// 问题:应该 Box(ProductFactory 需要)还是 &Box(ProductCachingProxy 需要)从 TProductFactory.fn product_from_text(&mut self, text: String) -> Box<dyn TProduct>; 编辑?

如果将代理缓存到 return Box,如何从没有 copying/cloning (TProductCache.get(..)) 的引用创建它?

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