Dyl*_*n L 1 generics iterator traits rust
我正在编写一个特征作为映射类型数据结构(例如std::collections::BTreeMap和std::collections::HashMap)的接口。这是我昨天提出的问题的后续,尽管它是独立的。
我有一个我似乎无法理解的终生问题。我在我所有的教科书、The Rust Reference、StackOverflow 等中寻找答案,但我一直无法弄清楚发生了什么。根据上一个问题的建议,我已经在以下代码中编写了近十几个变体,并且最终遇到了相同的情况。我希望有人能帮助我理解为什么gc3()不可能或者我做错了什么。我知道我完全有可能已经关注这个问题太久了,以至于错过了一些本应显而易见的简单内容。(游乐场)
use std::collections::hash_map::{HashMap, Iter};
fn main() {
gc1(&HashMap::new());
gc2(&HashMap::new());
gc3(HashMap::new());
}
// Works
fn gc1<'a>(map: &'a dyn GroupedCollection<'a, usize, usize, Iter<'a, usize, Vec<usize>>>) {
let _ = map.iter().collect::<Vec<_>>();
}
// Works
fn gc2<'a, M>(map: &'a M)
where
M: 'a + GroupedCollection<'a, usize, usize, Iter<'a, usize, Vec<usize>>>,
{
let _ = map.iter().collect::<Vec<_>>();
}
// Compiler error: `map` does not live long enough
fn gc3<'a, M>(map: M)
where
M: 'a + GroupedCollection<'a, usize, usize, Iter<'a, usize, Vec<usize>>>,
{
let _ = map.iter().collect::<Vec<_>>();
}
pub trait GroupedCollection<'a, K, V, I: 'a> {
fn iter(&'a self) -> I;
}
impl<'a, K, V> GroupedCollection<'a, K, V, Iter<'a, K, Vec<V>>> for HashMap<K, Vec<V>>
{
fn iter(&'a self) -> Iter<'a, K, Vec<V>> {
HashMap::iter(&self)
}
}
Run Code Online (Sandbox Code Playgroud)
error[E0597]: `map` does not live long enough
--> src/main.rs:27:13
|
23 | fn gc3<'a, M>(map: M)
| -- lifetime `'a` defined here
...
27 | let _ = map.iter().collect::<Vec<_>>();
| ^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `map` is borrowed for `'a`
28 | }
| - `map` dropped here while still borrowed
Run Code Online (Sandbox Code Playgroud)
编译器是否会抱怨,因为 产生的引用map.iter()在 的末尾被删除,collect()因为collect(self)消耗了迭代器?(我尝试通过分配给迭代器引用来解决这个问题'a: 'b,GroupedCollection但'b它似乎并没有解决问题:playground)
TL;DR:不要使用生命周期参数,使用 HRTB: where M: for<'a> GroupedCollection<'a, usize, usize, Iter<'a, usize, Vec<usize>>>。
'a是调用者选择的生命周期。假设调用者选择'static(通常,最好根据 验证生命周期'static)。map.iter()被脱糖为<M as GroupedCollection<'static, ...>>::iter(&map). <M as GroupedCollection<'static, ...>>::iter()需要&'a self,即&'static self。但map是一个局部变量,因此&map绝对不是 'static。繁荣。
它与引用一起使用,因为调用者不仅选择'a,还需要提供与其匹配的引用。如果它选择'static,它就必须提供&'static M,所以一切都很好。
解决方案?你想要一个被调用者选择的生命周期。也就是说,M实现我选择GroupedCollection的某个生命周期'a,而不是我的调用者。在 Rust 中没有办法表达这一点,但你可以说“M实现GroupedCollection任何生命周期”,显然这包括我将选择的生命周期。这是高级特质界限:M: for<'a> GroupedCollection<'a, ...>。所以:
fn gc3<M>(map: M)
where
M: for<'a> GroupedCollection<'a, usize, usize, Iter<'a, usize, Vec<usize>>>,
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
游乐场。
完美吗?不会。在某些情况下,可能M不会GroupedCollection在任何生命周期内实现,但会在我们选择的生命周期内实现。但如果没有 GAT,你就无法做得更好。
| 归档时间: |
|
| 查看次数: |
903 次 |
| 最近记录: |