“缓存代理"的正确所有权在锈? [英] The proper ownership for "caching proxy" in Rust?

查看:30
本文介绍了“缓存代理"的正确所有权在锈?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用 FactoryString 构建一个对象并有多个实现:1) 实际构建和 2) 缓存(存储在内存中HashMap).问题是,在#1 的情况下,它必须传递所有权,而在#2 HashMap 拥有该值的情况下,只能返回一个引用.

<预><代码>使用 std::collections::HashMap;//产品界面酒吧特质 TProduct {fn get_title(&self) ->&字符串;}//和具体的实现酒吧结构混凝土产品1 {}impl TProduct for ConcreteProduct1 {//...}酒吧结构混凝土产品2{}impl TProduct for ConcreteProduct2 {//...}//工厂接口酒吧特质 TProductFactory {fn product_from_text(&mut self, text: String) ->Box;//问题:它应该是 Box(ProductFactory 需要)还是 &Box(ProductCachingProxy 需要)?}//实际建筑工厂酒吧结构产品工厂{}impl TProductFactory for ProductFactory {fn product_from_text(&mut self, text: String) ->Box{//...//取决于某些条件Box::new(ConcreteProduct1::from_text(text));//必须传递所有权//或者Box::new(ConcreteProduct2::from_text(text));//必须传递所有权//...}}//缓存代理特质 TProductCache {fn put(&mut self, text: &String, product: Box<dyn TProduct>);fn get(&self, text: &String) ->选项<&Box<dyn TProduct>;fn clear(&mut self);}struct InMemoryProductCache {映射:HashMap>}impl InMemoryProductCache {fn new() ->自己 {返回 InMemoryProductCache {地图: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) ->选项<&Box<dyn TProduct>>{返回匹配 self.map.get(text) {一些(盒装产品)=>Some(boxed_product),//必须传递一个引用才能让它仍然拥有这个值无 =>没有任何}}fn clear(&mut self) {self.map.clear();}}struct ProductCachingProxy {product_factory: Box,缓存:Box}impl ProductCachingProxy {fn new_for_factory(product_factory: Box, cache: Box) ->自己 {返回 ProductCachingProxy {产品工厂,缓存}}}impl TProductFactory for ProductCachingProxy {fn product_from_text(&mut self, text: String) ->&Box<dyn TProduct>{//不能传递所有权让 boxed_product = 匹配 self.cache.get(&text) {一些(found_boxed_product)=>found_boxed_product,_ =>{//将创建委托给包装的 TProductFactory impl (`product_factory`)让 boxed_product = self.product_factory.product_from_text(text.clone());//...并放入缓存self.cache.put(&text, boxed_product);&boxed_product}};返回 boxed_product;}}

//问题:它应该是 Box(ProductFactory 需要)还是 &Box(ProductCachingProxy 需要)从 TProductFactory.fn product_from_text 返回(&mut self, text: String) ->Box; ?

如果缓存代理返回一个Box,如何在不复制/克隆的情况下从引用创建它(TProductCache.get(..))?

解决方案

Replace BoxRc (或者 Arc 如果你使用线程).它通过单一签名提供共享所有权和套件.另一种选择是使用 Cow,它是拥有和借用状态的枚举.

I'd like to use Factory to build an object from the String and have multiple impls: 1) actual building and 2) caching (stores in-memory in HashMap). The problem is that in case #1 it have to pass the ownership and in case #2 HashMap owns the value and a reference can be returned only.


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

// QUESTION: should it be Box (required for ProductFactory) or &Box (required for ProductCachingProxy) to be returned from TProductFactory.fn product_from_text(&mut self, text: String) -> Box<dyn TProduct>; ?

If caching proxy to return a Box, how can it be created from a reference without copying/cloning (TProductCache.get(..))?

解决方案

Replace Box with Rc (or Arc if you use threads). It provides shared ownership and suites both your cases with single signature. Another option is to use Cow that is a enum of owned and borrowed states.

这篇关于“缓存代理"的正确所有权在锈?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆