use std::collections::HashMap;
use std::hash::Hash;
struct Watchable<'a, K, V, W: Watcher<'a, K, V>> {
data: HashMap<K, V>,
watchers: Vec<W>,
}
trait Watcher<'a, K, V> {
fn before_new(&mut self, key: &'a K, value: &'a V);
}
struct IndexWatcher<'a, I: 'a, V: 'a> {
data: HashMap<&'a I, &'a V>,
indexer: fn(&V) -> &I,
}
impl<'a, K, V, I> Watcher<'a, K, V> for IndexWatcher<'a, I, V>
where I: Eq + Hash
{
fn before_new(&mut self, key: &'a K, value: &'a V) {
let index = (self.indexer)(value);
self.data.insert(index, value);
}
}
error[E0392]: parameter `'a` is never used
--> src/main.rs:4:18
|
4 | struct Watchable<'a, K, V, W: Watcher<'a, K, V>> {
| ^^ unused type parameter
|
= help: consider removing `'a` or using a marker such as `std::marker::PhantomData`
有没有办法删除一些生命周期注释?似乎一切都有相同的生命期a
。
起初,我没有任何具体的生命周期:
struct IndexWatcher<I, V> {
data: HashMap<&I, &V>,
indexer: fn(&V) -> &I,
}
编译器抱怨生命周期,所以我添加了它:
struct IndexWatcher<'a, I: 'a, V: 'a> {
data: HashMap<&'a I, &'a V>,
indexer: fn(&V) -> &I,
}
当我试图在没有生命期的情况下实现这个特性时:
trait Watcher<K, V> {
fn before_new(&mut self, key: &K, value: &V);
}
impl<'a, K, V, I> Watcher<K, V> for IndexWatcher<'a, I, V>
where I: Eq + Hash
{
fn before_new(&mut self, key: &K, value: &V) {
let index = (self.indexer)(value);
self.data.insert(index, value);
}
}
我收到了错误:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> <anon>:18:33
|
18 | self.data.insert(index, value);
| ^^^^^
|
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> <anon>:17:21
|
17 | let index = (self.indexer)(value);
| ^^^^^^^^^^^^^^^^^^^^^
|
因此,我的最终版本到处都有生命。
理想情况下,我想使用Watchable
中的特征,如下所示:
impl<K, V, W: Watcher<K, V>> Watchable<K, V, W>
where K: Eq + Hash {
fn insert(&mut self, k: K, v: V) -> Option<V> {
match self.data.entry(k) {
Occupied(mut occupied) => {
{
let k = occupied.key();
let old = occupied.get();
for watcher in &mut self.watchers {
watcher.before_change(k, &v, old);
}
}
let old = occupied.insert(v);
Some(old)
},
Vacant(vacant) => {
{
let k = vacant.key();
for watcher in &mut self.watchers {
watcher.before_new(k, &v);
}
}
vacant.insert(v);
None
}
}
}
}
trait Watcher<K, V> {
fn before_new(&mut self, key: &K, value: &V);
fn before_change(&mut self, key: &K, value: &V, old: &V);
}
答案 0 :(得分:2)
您可以使用higher-rank trait bound代替生命周期参数来消除错误:
struct Watchable<K, V, W: for<'a> Watcher<'a, K, V>> {
data: HashMap<K, V>,
watchers: Vec<W>,
}
但这并不能解决你的问题。 IndexWatcher
不会满足绑定for<'a> Watcher<'a, K, V>
,因为IndexWatcher<'a, I, V>
仅针对一个特定生命周期实现Watcher<'a, K, V>
,而不是针对所有可能的生命周期。
从根本上说,问题在于you're trying to put a value and a reference to that value in the same struct(间接)。也就是说,您的想法是观察者应该从Watchable
借用数据,但Watchable
也拥有观察者。请花点时间到read this question和Shepmaster的答案,了解为什么这个想法不起作用。
特别要注意的是,在Watchable
的{{1}}中插入条目或删除条目可能会导致任何观察者的引用无效,因为HashMap
需要重新分配存储,可能导致密钥和值的地址发生变化。
我要做的是将密钥和值包装在HashMap
(或Rc
中,如果您想跨线程共享Arc
。但是,从Watchable
中获取共享索引值可能会有问题。考虑将索引函数更改为Rc<V>
,并使索引函数返回克隆(如果克隆索引值太贵,它们可以是fn(&V) -> I
的克隆)或处理。