通用特征的终身问题

发布于 2025-01-26 11:55:00 字数 2658 浏览 1 评论 0原文

我正在通过MAP-TYPE数据结构(例如std :: Collections :: Btreemapstd :: Collections :: Hashmap)编写特征作为接口(例如std :: collections :: btreemap std :: collections :: collect>)。这是我昨天问的问题 ,尽管它是独立的。

我有一个我似乎无法理解的终生问题。我已经在所有教科书,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

78a741a3ceb61f19a1d4b84b882c95f3c95f3c94编译器抱怨是因为map.iter()collect()的末尾删除的参考? (我尝试通过将'a:'b分配给groupedCollection'b来解决此问题,但似乎没有要解决该问题:

I'm writing a trait as an interface over map-type data structures (e.g. std::collections::BTreeMap and std::collections::HashMap). This is a follow-up to a question I asked yesterday, though it stands on its own.

I'm having a lifetime issue I can't seem to understand. I've searched for answers in all my textbooks, The Rust Reference, StackOverflow, and more, and I haven't been able to figure out what's going on. I've written almost a dozen variants on the following code based on the suggestions from the previous question, and I wind up with the same situation. I'm hoping someone can help me understand either why gc3() is impossible or what I'm doing wrong. I know it's entirely possible I've had my nose in the problem for so long I'm missing something simple that should be obvious. (playground)

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

Is the compiler complaining because the references produced by map.iter() are dropped at the end of collect() because collect(self) consumes the iterator? (I've tried addressing this by assigning 'a: 'b to GroupedCollection and 'b to iterator references, but it doesn't seem to fix the issue: playground)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空袭的梦i 2025-02-02 11:55:00

tl; dr :不要使用寿命参数,使用hrtb:其中m:for&lt;'a&gt; groupedCollection&lt; a,usize,usize,iter&lt;


'a是呼叫者选择的寿命。假设呼叫者选择'static(通常,可以验证'static的生​​命值)。 map.iter()被解除为&lt; m作为groupedCollection&lt;'static,...&gt; :: iter(&amp; map)&lt; m作为groupedCollection&lt;'静态,... self。但是地图是一个本地变量,因此肯定是不是 'static。繁荣。

它可以使用引用,因为呼叫者不仅选择'a,还需要提供与之匹配的参考。如果它会选择'static,则必须提供&amp;'静态M,因此一切都很好。

解决方案?您想要一个 callee 选择的寿命。也就是说,m实现groupedCollection在某些生命周期'a 我选择的,而不是我的呼叫者。在Rust中无法表达这一点,但是您可以说“ m实现groupedCollection for a nothy lifetime”,显然包括寿命我会选择的。这是较高的特征界m:m:for&lt;'a&gt; ; groupedCollection&lt;'a,...&gt;。因此:

fn gc3<M>(map: M)
where
    M: for<'a> GroupedCollection<'a, usize, usize, Iter<'a, usize, Vec<usize>>>,
{
    // ...
}

这是完美的吗?否。在某些情况下,m未实现 lifetime的 groupedCollection ,但它确实可以选择我们选择的寿命。但是,没有GAT,您将无法做得更好。

TL;DR: Don't use a lifetime parameter, use HRTB: where M: for<'a> GroupedCollection<'a, usize, usize, Iter<'a, usize, Vec<usize>>>.


'a is a caller-chosen lifetime. Suppose the caller choose 'static (in general, it is good to validate lifetimes against 'static). map.iter() is desugared to <M as GroupedCollection<'static, ...>>::iter(&map). <M as GroupedCollection<'static, ...>>::iter() requires &'a self, i.e. &'static self. But map is a local variable, and thus &map is definitely not 'static. Boom.

It works with references because the caller not only choose 'a, it also needs to provide a reference that matches it. If it'll choose 'static, it will have to provide &'static M and so everything is fine.

The solution? You want a callee-chosen lifetime. That is, M implements GroupedCollection for some lifetime 'a I choose, not my caller. There is no way to express that in Rust, but you can say "M implements GroupedCollection for any lifetime", and obviously that includes the lifetime I will choose. This is Higher-Ranked Trait Bounds: M: for<'a> GroupedCollection<'a, ...>. So:

fn gc3<M>(map: M)
where
    M: for<'a> GroupedCollection<'a, usize, usize, Iter<'a, usize, Vec<usize>>>,
{
    // ...
}

Playground.

Is it perfect? No. There may be cases where M doesn't implement GroupedCollection for any lifetime, but it does for the lifetime we choose. But you cannot do better without GAT.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文