与特质相关的类型生命周期和自我

发布于 2025-02-03 05:03:42 字数 2222 浏览 2 评论 0 原文

我有一个结构,该结构包装了 std :: Cell :: Ref ,并通过参考基础值提供访问。这样的事情:

use std::cell::Ref;

struct IntAccess<'a> {
    i: Ref<'a, i32>,
}

impl IntAccess<'_> {
    fn get(&self) -> &i32 {
        &self.i
    }
}

这可以正常工作。由于我有这样的多个结构,因此我想定义一个常见的特征:

trait Access {
    type Item;
    fn get(&self) -> Self::Item;
}

但是,我在尝试实现 access for intaccess 时会遇到麻烦:

impl<'a> Access for IntAccess<'a> {
    type Item = &'a i32;

    fn get(&self) -> Self::Item {
        &self.i
    }
}

它会失败以下错误:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:23:9
   |
23 |         &self.i
   |         ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/main.rs:22:12
   |
22 |     fn get(&self) -> Self::Item {
   |            ^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:23:9
   |
23 |         &self.i
   |         ^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
  --> src/main.rs:19:6
   |
19 | impl<'a> Access for IntAccess<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:22:33
   |
22 |       fn get(&self) -> Self::Item {
   |  _________________________________^
23 | |         &self.i
24 | |     }
   | |_____^
   = note: expected `<IntAccess<'a> as Access>`
              found `<IntAccess<'_> as Access>`

我认为我有点会得到编译器试图告诉我的内容:我试图借用 self.i ,它与 self的寿命无关的匿名寿命:项目'a )。因此,似乎需要的是以某种方式将 self in get 中的的寿命与寿命'a 联系起来。有办法这样做吗?

我必须承认,我没有完全掌握这个问题。由于我将lifetime 'a 传递给 ref ,并且 ref 内部存储此寿命的参考,在我看来,它应该以某种方式可以从中获得使用Lifetime 的参考,而无需将 self 也与此生命周期明确联系。那我在这里想念什么?

I have a struct that wraps a std::cell::Ref and provides access by reference to the underlying value. Something like this:

use std::cell::Ref;

struct IntAccess<'a> {
    i: Ref<'a, i32>,
}

impl IntAccess<'_> {
    fn get(&self) -> &i32 {
        &self.i
    }
}

This works fine. Since I have multiple structs like this, I'd like to define a common trait:

trait Access {
    type Item;
    fn get(&self) -> Self::Item;
}

However, I get into trouble when trying to implement Access for IntAccess:

impl<'a> Access for IntAccess<'a> {
    type Item = &'a i32;

    fn get(&self) -> Self::Item {
        &self.i
    }
}

It fails with the following error:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:23:9
   |
23 |         &self.i
   |         ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/main.rs:22:12
   |
22 |     fn get(&self) -> Self::Item {
   |            ^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:23:9
   |
23 |         &self.i
   |         ^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
  --> src/main.rs:19:6
   |
19 | impl<'a> Access for IntAccess<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:22:33
   |
22 |       fn get(&self) -> Self::Item {
   |  _________________________________^
23 | |         &self.i
24 | |     }
   | |_____^
   = note: expected `<IntAccess<'a> as Access>`
              found `<IntAccess<'_> as Access>`

I think I kind of get what the compiler is trying to tell me: I'm trying to borrow self.i which has an anonymous lifetime unrelated to the lifetime of Self::Item ('a). So what seems to be needed is to somehow tie the lifetime of self in get to the lifetime 'a. Is there a way to do this?

I have to admit that I don't fully grasp the problem. Since I pass the lifetime 'a to the Ref, and Ref internally stores a reference with this lifetime, it seems to me that it should somehow be possible to get a reference with lifetime 'a out of it without having to explicitly tie self to this lifetime as well. So what am I missing here?

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

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

发布评论

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

评论(1

空城旧梦 2025-02-10 05:03:42

您的理解是正确的。关于您的疑问,让我们命名寿命以进行更轻松的调试:

impl<'a> Access for IntAccess<'a> {
    type Item = &'a i32;

    fn get<'b>(&'b self) -> Self::Item {
        &self.i
    }
}

self 具有类型&amp;'b intaccess&lt;'a&gt; 'b ' - self , IE可以存在(否则,它将包含一个悬空的参考)。

因此,我们不能借用 self 超过'b - 或我们可以做类似的事情:

let v: IntAccess<'a>;
let inner: &'a i32 = {
    let r: &'b IntAccess<'a> = &v;
    <IntAccess<'a> as Access>::get(r)
}
let mut_r: &mut IntAccess<'a> = &mut v;

我们既有共享和可变的参考(一部分) 内部

如果没有 self 的生​​命周期相关的相关类型”:

#![feature(generic_associated_types)]

trait Access {
    type Item<'a>
    where
        Self: 'a;
    fn get<'a>(&'a self) -> Self::Item<'a>;
    // Or, with lifetime elision:
    // fn get(&self) -> Self::Item<'_>;
}

impl<'a> Access for IntAccess<'a> {
    type Item<'b> = &'b i32
    where
        'a: 'b;

    fn get<'b>(&'b self) -> Self::Item<'b> {
        &self.i
    }
}

我们可以在稳定上这样做吗?我们可以模仿。我们将无需实现访问 intaCcess 本身,而是为对其进行实施

trait Access {
    type Item;
    fn get(self) -> Self::Item;
}

impl<'a, 'b> Access for &'b IntAccess<'a> {
    type Item = &'b i32;
    fn get(self) -> &'b i32 {
        &self.i
    }
}

nightly&amp;mode=debug&;工作,因此不能完全替代GAT,而是在这种情况下足够好。

Your understanding is correct. About your doubt, let's name the lifetimes for easier debugging:

impl<'a> Access for IntAccess<'a> {
    type Item = &'a i32;

    fn get<'b>(&'b self) -> Self::Item {
        &self.i
    }
}

self has the type &'b IntAccess<'a>. 'b is shorter than or equal to 'a - that is required for self to be well-formed, i.e. able to exist (otherwise, it would contain a dangling reference).

For that reason, we cannot borrow self for more than 'b - or we could do something like:

let v: IntAccess<'a>;
let inner: &'a i32 = {
    let r: &'b IntAccess<'a> = &v;
    <IntAccess<'a> as Access>::get(r)
}
let mut_r: &mut IntAccess<'a> = &mut v;

And we have both a shared and a mutable reference to (parts of) inner!

Your problem cannot be solved fully without Generic Associated Types. They allow you to parameterize an associated type by a lifetime, making it able to express "I want to return this associated type tied to the lifetime of self":

#![feature(generic_associated_types)]

trait Access {
    type Item<'a>
    where
        Self: 'a;
    fn get<'a>(&'a self) -> Self::Item<'a>;
    // Or, with lifetime elision:
    // fn get(&self) -> Self::Item<'_>;
}

impl<'a> Access for IntAccess<'a> {
    type Item<'b> = &'b i32
    where
        'a: 'b;

    fn get<'b>(&'b self) -> Self::Item<'b> {
        &self.i
    }
}

Playground.

Can we do that on stable? We can emulate that. Instead of implementing Access for IntAccess itself, we will implement it for a reference to it!

trait Access {
    type Item;
    fn get(self) -> Self::Item;
}

impl<'a, 'b> Access for &'b IntAccess<'a> {
    type Item = &'b i32;
    fn get(self) -> &'b i32 {
        &self.i
    }
}

Playground

This does not always work, and thus is not a full replacement to GATs, but is good enough in this case.

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