“缓存代理"的正确所有权在锈? [英] The proper ownership for "caching proxy" in Rust?
问题描述
我想使用 Factory
从 String
构建一个对象并有多个实现:1) 实际构建和 2) 缓存(存储在内存中HashMap
).问题是,在#1 的情况下,它必须传递所有权,而在#2 HashMap 拥有该值的情况下,只能返回一个引用.
//问题:它应该是 Box
(ProductFactory 需要)还是 &Box
(ProductCachingProxy 需要)从 TProductFactory.fn product_from_text 返回(&mut self, text: String) ->Box
?
如果缓存代理返回一个Box
,如何在不复制/克隆的情况下从引用创建它(TProductCache.get(..)
)?
Replace Box
为 Rc
(或者 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屋!