【发布时间】:2021-12-12 00:13:02
【问题描述】:
我正在创建一个库,它试图成为一个 Cache 结构,该结构包装了一些结构,该结构将成为检索“新鲜数据”的组件,例如通过一些 HTTP 请求;还有一个后端字段,它是通过包装组件检索的数据的实际缓存后端。
在检索一些新数据后尝试“刷新”缓存中的数据时,我遇到了一些问题。
use std::collections::HashMap;
pub trait Cacheable<K, V>
where K: std::cmp::Eq + std::hash::Hash
{
fn get(&self, k: &K) -> Option<&V>;
fn set(&mut self, k: K, v: V);
fn del(&mut self, k: &K);
}
pub struct Cache<'a, K, V>
where K: std::cmp::Eq + std::hash::Hash
{
wrapped: &'a dyn Cacheable<K, V>,
backend: Box<dyn Cacheable<K, V>>,
}
impl<'a, K, V> Cache<'a, K, V>
where K: std::cmp::Eq + std::hash::Hash + 'static,
V: 'static,
{
fn New(wrapped: &'a dyn Cacheable<K, V>, backend_type: BackendType) -> Self {
let backend = match backend_type {
BackendType::Memory => MemoryBackend::<K, V>::New(),
};
Cache {
wrapped: wrapped,
backend: Box::new(backend),
}
}
fn get(&mut self, k: &K) -> Option<&V> {
// PROBLEM 1:
// Borrow backend here as immutable
if let Some(v) = self.backend.get(k) {
return Some(v)
}
if let Some(v) = self.wrapped.get(k) {
let cache_k = *k.clone(); // PROBLEM 2: How to clone reference value?
let cache_v = *v.clone(); // PROBLEM 2: How to clone reference value?
// PROBLEM 1:
// Borrow backend here as mutable
self.backend.set(cache_k, cache_v);
return Some(v)
}
None
}
}
pub enum BackendType {
Memory
}
pub struct MemoryBackend<K, V>
where K: std::cmp::Eq + std::hash::Hash
{
data: HashMap<K, V>,
}
impl<K, V> Cacheable<K, V> for MemoryBackend<K, V>
where K: std::cmp::Eq + std::hash::Hash
{
fn get(&self, k: &K) -> Option<&V> {
self.data.get(k)
}
fn set(&mut self, k: K, v: V) {
self.data.insert(k, v);
}
fn del(&mut self, k: &K) {
self.data.remove(k);
}
}
impl<K, V> MemoryBackend<K, V>
where K: std::cmp::Eq + std::hash::Hash
{
fn New() -> Self {
MemoryBackend {
data: HashMap::<K, V>::new(),
}
}
}
问题 1
可变引用和不可变引用可能共存。这里最好的选择是什么?
我尝试更改 get 方法签名以返回 Option<V> 而不是 Option<&V> 但这也导致了问题 2,我似乎无法克隆共享的值参考。
问题 2
move occurs because value has type `K`, which does not implement the `Copy` trait
help: consider borrowing here: `&*k.clone()`"
AFAIK 我不想将 Copy 特征设置为 V 的绑定,因为它可能不是一个简单的类型,并且宁愿克隆它的值而不是将其设置为 API 限制。我似乎无法解决这个问题。
【问题讨论】:
-
RefCell应该可以帮助您使get接受&self,同时仍然能够更改backend -
如果你先
self.backend.set,然后return self.backend.get(cache_k);,问题2可以很容易解决,除非性能太关键
标签: rust