Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
185 views
in Technique[技术] by (71.8m points)

traits - The proper ownership for "caching proxy" in Rust?

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(..))?

question from:https://stackoverflow.com/questions/65920550/the-proper-ownership-for-caching-proxy-in-rust

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...