Zoi*_*erg 13 generics iterator lifetime rust
我想编写一个通用的函数,它接受任何不可改变借来的迭代容器如数组,Vec,BTreeSet,等.由于这个功能是我实现一个特质的一部分,我不能改变它的签名,所以它不是可以直接将迭代器作为参数,我也不能将任何生命周期参数引入函数签名.
我试图在Rust中实现观察者模式.观察者和观察者看起来如下:
struct Observable<T> {
value: T,
}
impl<T> Observable<T> {
pub fn get(&self) -> &T {
&self.value
}
}
trait Observer<T> {
fn update(&self, &Observable<T>);
}
Run Code Online (Sandbox Code Playgroud)
(省略了与我的问题无关的一些功能)
现在我的目标是编写一个可以与任意可迭代容器一起使用的观察器,该容器包含可以赋值的项.它应该跟踪容器中项目的值的总和,因此保持当前的总和以及计算任何项目的值的函数.它应该实现Observer特征,以便每次容器更改时都可以更新总和.
use std::cell::RefCell;
struct SumObserver<T> {
current_sum: RefCell<i64>,
get_value: Fn(&T) -> i64,
}
Run Code Online (Sandbox Code Playgroud)
我试图让update函数编译很长一段时间都没有成功.以下是我尝试过的函数版本之一:
impl<'a, T, L> Observer<L> for SumObserver<T>
where
&'a L: IntoIterator<Item = &'a T>,
{
fn update(&self, observable: &Observable<L>) {
let mut sum: i64 = 0;
for item in observable.get() {
sum += (self.get_value)(item);
}
*self.current_sum.borrow_mut() = sum;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,编译器抱怨两种参数类型T并且L可能不够长寿:
error[E0309]: the parameter type `T` may not live long enough
--> src/lib.rs:22:1
|
22 | impl<'a, T, L> Observer<L> for SumObserver<T>
| ^ - help: consider adding an explicit lifetime bound `T: 'a`...
| _|
| |
23 | | where
24 | | &'a L: IntoIterator<Item = &'a T>,
25 | | {
... |
32 | | }
33 | | }
| |_^
|
note: ...so that the reference type `&'a T` does not outlive the data it points at
--> src/lib.rs:22:1
|
22 | / impl<'a, T, L> Observer<L> for SumObserver<T>
23 | | where
24 | | &'a L: IntoIterator<Item = &'a T>,
25 | | {
... |
32 | | }
33 | | }
| |_^
Run Code Online (Sandbox Code Playgroud)
如果整个函数体被注释掉,则错误消息甚至保持不变.如果我也删除where-clause,编译工作.
如果我遵循编译器的建议,为参数类型添加显式生存期限:
impl<'a, T: 'a, L: 'a> Observer<L> for SumObserver<T>
Run Code Online (Sandbox Code Playgroud)
编译器给出以下错误:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:28:32
|
28 | for item in observable.get() {
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 26:5...
--> src/lib.rs:26:5
|
26 | / fn update(&self, observable: &Observable<L>) {
27 | | let mut sum: i64 = 0;
28 | | for item in observable.get() {
29 | | sum += (self.get_value)(item);
30 | | }
31 | | *self.current_sum.borrow_mut() = sum;
32 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:28:21
|
28 | for item in observable.get() {
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 22:6...
--> src/lib.rs:22:6
|
22 | impl<'a, T: 'a, L: 'a> Observer<L> for SumObserver<T>
| ^^
= note: ...so that the types are compatible:
expected std::iter::IntoIterator
found std::iter::IntoIterator
Run Code Online (Sandbox Code Playgroud)
我不明白这个函数的生命周期问题.在调用此函数的任何时候,编译器应确保借用observable至少持续到函数返回.那时,任何借款observable都超出了范围.
Mat*_* M. 12
这是较高等级特征界(HRTB)的一个案例.
问题的关键是,你不希望&L实现IntoIterator<Item = &T>的一个生命周期,但对于所有的潜在寿命L可能正好有.
在这种情况下,您需要使用更高级别的特征绑定:for<'a>将负责引入生命周期名称,同时向编译器发信号通知使用它的子句应对所有可能的值有效'a.
这意味着:
impl<T, L> Observer<L> for SumObserver<T>
where
for<'a> &'a L: IntoIterator<Item = &'a T>,
{
fn update(&self, observable: &Observable<L>) {
let mut sum: i64 = 0;
for item in observable.get() {
sum += (self.get_value)(item);
}
*self.current_sum.borrow_mut() = sum;
}
}
Run Code Online (Sandbox Code Playgroud)
编译(至少是孤立的).
也可以看看:
| 归档时间: |
|
| 查看次数: |
3549 次 |
| 最近记录: |