[英]how to solve cyclic-dependency & Iterator lifetime problem?
Rustaceans.锈菌类。 when I start to write a BloomFilter example in rust.
当我开始在 rust 中编写 BloomFilter 示例时。 I found I have serveral problems have to solve.
我发现我有几个问题需要解决。 I struggle to solve them but no progress in a day.
我努力解决它们,但一天没有进展。 I need help, any suggestion will help me a lot, Thanks.
我需要帮助,任何建议都会对我有很大帮助,谢谢。
// let bits = self.hash(value); // how to solve such lifetime error without use 'static storage?
// Below is a workaround code but need to computed in advanced.
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.set(bits);
bloom_filter
?bloom_filter
?// cyclic-dependency:
// RedisCache -> BloomFilter -> Storage
// | ^
// ------------<impl>------------
//
// v--- cache ownership has moved here
let filter = BloomFilter::by(Box::new(cache));
cache.1.replace(filter);
null
value, How can I solve the cyclic-dependency initialization without any stubs?null
值,如何在没有任何存根的情况下解决循环依赖初始化?let mut cache = RedisCache(
Client::open("redis://localhost").unwrap(),
// I found can use Weak::new() to solve it,but need to downgrade a Rc reference.
// v-- need a BloomFilter stub to create RedisCache
RefCell::new(BloomFilter::new()),
);
#![allow(unused)]
mod bloom_filter {
use std::{hash::Hash, marker::PhantomData};
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
pub trait Storage {
fn set(&mut self, bits: BitsIter);
fn contains_all(&self, bits: BitsIter) -> bool;
}
pub struct BloomFilter<T: Hash>(Box<dyn Storage>, PhantomData<T>);
impl<T: Hash> BloomFilter<T> {
pub fn new() -> BloomFilter<T> {
return Self::by(Box::new(ArrayStorage([0; 5000])));
struct ArrayStorage<const N: usize>([u8; N]);
impl<const N: usize> Storage for ArrayStorage<N> {
fn set(&mut self, bits: BitsIter) {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.for_each(|index| self.0[index] = 1);
}
fn contains_all(&self, bits: BitsIter) -> bool {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.all(|index| self.0[index] == 1)
}
}
}
pub fn by(storage: Box<dyn Storage>) -> BloomFilter<T> {
BloomFilter(storage, PhantomData)
}
pub fn add(&mut self, value: T) {
// let bits = self.hash(value); // how to solve such lifetime error?
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.set(bits);
}
pub fn contains(&self, value: T) -> bool {
// lifetime problem same as Self::add(T)
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.contains_all(bits)
}
fn hash<'a, H: Hash + 'a>(&self, _value: H) -> Box<dyn Iterator<Item = u64> + 'a> {
todo!()
}
}
}
mod spi {
use super::bloom_filter::*;
use redis::{Client, Commands, RedisResult};
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
pub struct RedisCache<'a>(Client, RefCell<BloomFilter<&'a str>>);
impl<'a> RedisCache<'a> {
pub fn new() -> RedisCache<'a> {
let mut cache = RedisCache(
Client::open("redis://localhost").unwrap(),
// v-- need a BloomFilter stub to create RedisCache
RefCell::new(BloomFilter::new()),
);
// v--- cache ownership has moved here
let filter = BloomFilter::by(Box::new(cache));
cache.1.replace(filter);
return cache;
}
pub fn get(&mut self, key: &str, load_value: fn() -> Option<String>) -> Option<String> {
let filter = self.1.borrow();
if filter.contains(key) {
if let Ok(value) = self.0.get::<&str, String>(key) {
return Some(value);
}
if let Some(actual_value) = load_value() {
let _: () = self.0.set(key, &actual_value).unwrap();
return Some(actual_value);
}
}
return None;
}
}
impl<'a> Storage for RedisCache<'a> {
fn set(&mut self, bits: BitsIter) {
todo!()
}
fn contains_all(&self, bits: BitsIter) -> bool {
todo!()
}
}
}
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
In this case, the object in the box must be valid for the 'static
lifetime.在这种情况下,盒子中的 object 必须在
'static
生命周期”内有效。 This isn't the case for the iterator returned by hash
- its limited to the lifetime of self
. hash
返回的迭代器不是这种情况 - 它仅限于self
的生命周期。
Try replacing with:尝试替换为:
pub type BitsIter<'a> = Box<dyn Iterator<Item = u64> + 'a>;
Or using generics instead of boxed trait objects.或者使用 generics 代替盒装特征对象。
So your RedisClient
needs a BloomFilter
, but the BloomFilter
also needs the RedisClient
?所以你的
RedisClient
需要一个BloomFilter
,但BloomFilter
也需要RedisClient
?
Your BloomFilter
should not use the RedisCache
that itself uses the BloomFilter
- that's a recipe for infinitely recursing calls (how do you know what calls to RedisCache::add
should update the bloom filter and which calls are from the bloom filter?).您的
BloomFilter
不应使用本身使用RedisCache
的BloomFilter
- 这是无限递归调用的秘诀(您怎么知道对RedisCache::add
的哪些调用应该更新布隆过滤器以及哪些调用来自布隆过滤器?)。
If you really have to, you need some form of shared ownership, like Rc
or Arc
.如果你真的需要,你需要某种形式的共享所有权,比如
Rc
或Arc
。 Your BloomFilter
will also need to use a weak reference, or else the two objects will refer to each other and will never free.您的
BloomFilter
还需要使用弱引用,否则这两个对象将相互引用并且永远不会释放。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.