我正在撰寫一個特征作為映射型別資料結構(例如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)
}
}
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
編譯器是否抱怨,因為產生的參考map.iter()
在末尾被丟棄,collect()
因為collect(self)
消耗了迭代器?(我嘗試通過分配'a: 'b
給GroupedCollection
和'b
給迭代器參考來解決這個問題,但它似乎并沒有解決這個問題:操場)
uj5u.com熱心網友回復:
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
。Butmap
是一個區域變數,因此&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>>>,
{
// ...
}
游樂場。
完美嗎?不,可能存在M
不會在任何生命周期內實作GroupedCollection
的情況,但它會在我們選擇的生命周期內實作。但如果沒有 GAT,您將無法做得更好。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/470398.html
上一篇:使函式實體化其泛型引數